#+begin_src elisp tangle: no :results none :exports none
(setq pwd (file-name-directory buffer-file-name))
(setq name (file-name-nondirectory (substring buffer-file-name 0 -4)))
(setq lib (concat pwd "lib/"))
(setq testdir (concat pwd "test/"))
(setq mli (concat lib name ".mli"))
(setq ml  (concat lib name ".ml"))
(setq test-ml  (concat testdir name ".ml"))
(org-babel-tangle)
#+end_src 

*  Range
  :PROPERTIES:
  :header-args: :noweb yes :comments both
  :END:

  A range is a sorted list of integers in an interval.
  
  - ~"[a-b]"~ : range between a and b (included)
  - ~"[a]"~   : the list with only one integer a
  - ~"a"~     : equivalent to "[a]"
  - ~"[36-53,72-107,126-131]"~ represents the list of integers
    [ 37 ; 37 ; 38 ; ... ; 52 ; 53 ; 72 ; 73 ; ... ; 106 ; 107 ; 126 ; 127 ; ... ; 130 ; 131 ].

** Type

   <<<~Range.t~>>>
   #+begin_src ocaml :tangle (eval mli)
type t
   #+end_src

   #+begin_src ocaml :tangle (eval ml) :exports none
type t = int list
   #+end_src

** Conversion

   #+begin_src ocaml :tangle (eval mli)
val of_string   : string -> t
val to_string   : t -> string
val to_int_list : t -> int list
   #+end_src

   #+begin_src ocaml :tangle (eval ml) :exports none
let to_int_list r = r

let expand_range r =
  match String.split_on_char '-' r with
  | s :: f :: [] ->
      begin
        let start = int_of_string s
        and finish =  int_of_string f
        in
        assert (start <= finish) ;
        let rec do_work = function
          | i when i=finish -> [ i ]
          | i     -> i::(do_work (i+1))
        in do_work start
      end
  | r :: [] -> [int_of_string r]
  | [] -> []
  | _ -> invalid_arg "Only one range expected"


let of_string s =
  match s.[0] with
  | '0' .. '9' -> [ int_of_string s ]
  | _ ->
      assert (s.[0] = '[') ;
      assert (s.[(String.length s)-1] = ']') ;
      let s = String.sub s 1 ((String.length s) - 2) in
      let l = String.split_on_char ',' s in
      let l = List.map expand_range l in
      List.concat l
      |> List.sort_uniq compare


let to_string l =
  "[" ^
  (List.map string_of_int l
   |> String.concat ",") ^
  "]"

   #+end_src


** Printers

   #+begin_src ocaml :tangle (eval mli)
val pp : Format.formatter -> t -> unit
   #+end_src

   #+begin_src ocaml :tangle (eval ml) :exports none
let pp ppf t =
  Format.fprintf ppf "@[%s@]" (to_string t)
   #+end_src

