Source

ocaml-indent / tokenstr.ml

Full commit
open Pos
open Reader
module Parser = Xparser
open Parser

module Stream = struct
  type 'a desc = 
    | Null
    | Cons of 'a * 'a t

  and 'a t = 'a desc lazy_t
end

type 'a info = {
  token        : 'a;
  region       : Region.t;
  substr       : string;
  space        : Region.t * string;
  mutable chan : in_channel option;
}

let close i = match i.chan with
  | None -> ()
  | Some ch -> close_in ch; i.chan <- None

let of_channel ic = 
  let reader = LexReader.create_from_channel ic in
  let rec loop last_region = 
    let token = 
      try
        LexReader.lex reader Lexer.token 
      with
      | Lexer.Error (e, _loc) ->
          Format.eprintf "%a@." Lexer.report_error e;
          assert false
    in
    let region = LexReader.region reader in
    (* token's string *)
    let substr = LexReader.current_substring reader in

    let space_between = 
      let last_end = (snd last_region).Position.pos_cnum in
      LexReader.substring 
        reader last_end ((fst region).Position.pos_cnum - last_end)
    in
    let space_between_region = (snd last_region, fst region) in

    Cons ({ token; region; substr; space = space_between_region, space_between },
          begin match token with
          | EOF -> 
              let null = Lazy.lazy_from_val (Null icoptref) in
              close null;
              null
          | _ -> lazy (loop region)
          end,
            icoptref)
  in
  { 
    chan = Some ic }
    lazy (loop Region.zero)
  with
  | e -> raise e

let of_path path =
  let ic = open_in path in
  of_channel ic

let destr = function
  | lazy Null _ -> None
  | lazy (Cons (car, cdr, _)) -> Some (car, cdr)