#lang scheme/base
(require "depend.ss"
         "util.ss"
         "input.ss" 
         ) 
(define (return v (size 0)) 
  (lambda (in)
    (values v
            (new-input in size))))
(define-struct failed (pos) #:prefab)
(define (succeeded? v) (not (failed? v))) 
(define (fail in) 
  (values (make-failed (input-pos in))
          in)) 
(define (SOF in) 
  ((if (= (input-pos in) 0)
       (return 'sof)
       fail) in)) 
(define (item peek isa? satisfy? size) 
  (lambda (in) 
    (let ((v (peek in))) 
      ((if (and (isa? v) (satisfy? v))
           (return v (size v))
           fail) in))))
(define (bytes= bytes) 
  (let ((size (bytes-length bytes)))
    (item (peek-bytes* size) 
          bytes?
          (lambda (b) 
            (bytes=? b bytes))
          (the-number size))))
(define (string= s (comp? string=?))
  (let ((size (string-bytes/utf-8-length s)))
    (item (peek-string* size)
          string?
          (lambda (str)
            (comp? str s))
          (the-number size))))
(define (string-ci= s) 
  (string= s string-ci=?))
(define (byte-when satisfy? (isa? byte?) (size (the-number 1)))
  (item peek-byte* isa? satisfy? size))
(define any-byte (byte-when identity))
(define (byte= b) (byte-when (lambda (v)
                               (= b v)))) 
(define EOF (byte-when identity eof-object? (the-number 0)))
(define (bits= bits)
  (byte-when (lambda (b) (= b (bits->byte bits)))))
(define (byte-in bytes) 
  (byte-when (lambda (b) (member b bytes))))
(define (byte-not-in bytes)
  (byte-when (lambda (b) (not (member b bytes)))))
(define (byte-between lb hb)
  (byte-when (lambda (b) (<= lb b hb)))) 
(define (byte-not-between lb hb)
  (byte-when (compose not (lambda (b) (<= lb b hb)))))
(define (char-when satisfy?)
  (item peek-char* char? satisfy? char-utf-8-length)) 
(define any-char (char-when identity))
(define (char= c (comp? char=?) (trans identity)) 
  (char-when (lambda (v) (trans (comp? c v)))))
(define (char-ci= c) (char= c char-ci=?))
(define (char-not= c (comp? char=?)) (char= c comp? not))
(define (char-ci-not= c) (char-not= char-ci=?))
(define (char-between lc hc (comp? char<=?) (trans identity)) 
  (char-when (lambda (v) (trans (comp? lc v hc)))))
(define (char-ci-between lc hc) (char-between lc hc char-ci<=?))
(define (char-not-between lc hc (comp? char<=?))
  (char-between lc hc comp? not))
(define (char-ci-not-between lc hc) (char-not-between lc hc char-ci<=?))
(define (char-in chars (comp? char=?) (trans identity))
  (char-when (lambda (v) 
               (trans (memf (lambda (c)
                              (comp? c v)) 
                            chars)))))
(define (char-ci-in chars) (char-in chars char-ci=?))
(define (char-not-in chars (comp? char=?))  (char-in chars comp? not))
(define (char-ci-not-in chars) (char-not-in chars char-ci=?))
(define (literal p) 
  (cond ((char? p) (char= p)) 
        ((byte? p) (byte= p)) 
        ((string? p) (string= p)) 
        ((bytes? p) (bytes= p)) 
        (else p))) 
(define (literal-ci p) 
  (cond ((char? p) (char-ci= p)) 
        ((string? p) (string-ci= p)) 
        (else (literal p)))) 
(define Literal/c (or/c string? bytes? char? byte?))
(define Literal-Parser/c (or/c Literal/c Parser/c))
(provide return
         (struct-out failed) 
         succeeded? 
         fail
         SOF
         item
         bytes=
         string=
         string-ci= 
         byte-when
         any-byte
         byte=
         EOF
         bits=
         byte-in
         byte-not-in
         byte-between
         byte-not-between
         char-when
         any-char
         char=
         char-ci=
         char-not=
         char-ci-not=
         char-between
         char-ci-between
         char-not-between
         char-ci-not-between
         char-in
         char-ci-in 
         char-not-in
         char-ci-not-in 
         literal 
         literal-ci 
         Literal/c
         Literal-Parser/c
         )