(* Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
 *    Jagannathan, and Stephen Weeks.
 * Copyright (C) 1997-2000 NEC Research Institute.
 *
 * MLton is released under a BSD-style license.
 * See the file MLton-LICENSE for details.
 *)

structure Reader: READER =
struct

open Int

type ('a, 'b) reader = 'b -> ('a * 'b) option

fun list (reader: ('a, 'b) reader): ('a list, 'b) reader =
   fn state =>
   let
      fun loop (state, accum) =
         case reader state of
            NONE => SOME (rev accum, state)
          | SOME (a, state) => loop (state, a :: accum)
   in loop (state, [])
   end

fun readerN (reader: ('a, 'b) reader, n: int): ('a list, 'b) reader =
   fn (state :'b) =>
   let
      fun loop (n, state, accum) =
         if n <= 0
            then SOME (rev accum, state)
         else case reader state of
            NONE => NONE
          | SOME (x, state) => loop (n - 1, state, x :: accum)
   in loop (n, state, [])
   end

fun ignore f reader =
   let
      fun loop state =
         case reader state of
            NONE => NONE
          | SOME (x, state) =>
               if f x
                  then loop state
               else SOME (x, state)
   in loop
   end
val _ = ignore

fun map (f: 'a -> 'c) (reader: ('a, 'b) reader): ('c, 'b) reader =
   fn (b: 'b) =>
   case reader b of
      NONE => NONE
    | SOME (a, b) => SOME (f a, b)

fun mapOpt (f: 'a -> 'c option) (reader: ('a, 'b) reader): ('c, 'b) reader =
   fn (b: 'b) =>
   case reader b of
      NONE => NONE
    | SOME (a, b) =>
         case f a of
            NONE => NONE
          | SOME c => SOME (c, b)

fun reader2 reader =
   map (fn [y, z] => (y, z) | _ => raise Fail "Reader.reader2")
   (readerN (reader, 2))
val _ = reader2

fun reader3 reader =
   map (fn [x, y, z] => (x, y, z) | _ => raise Fail "Reader.reader3")
   (readerN (reader, 3))

fun reader4 reader =
   map (fn [w, x, y, z] => (w, x, y, z) | _ => raise Fail "Reader.reader4")
   (readerN (reader, 4))

end   
