(load #P"../src/utils")
(load #P"../src/parser")
(use-package :utils)

; some tests for char
(let ((obj (p:new "abc")))
  (mvbind (c _) (funcall (p:char #\a) obj)
    (assert (eql c #\a)))
  (mvbind (c _) (funcall (p:char #\b) obj)
    (assert (eql c p:fail))))

(let ((obj (p:new "")))
  (mvbind (c _) (funcall (p:char #\a) obj)
    (assert (eql c p:fail))))

; some tests for eof
(let ((obj (p:new)))
  (mvbind (x _) (funcall p:eof obj)
    (assert (eql x 'p:eof))))

; some tests for other
(let* ((obj (p:new "ab")))
  (mvbind (x _) (funcall (p:other (p:char #\a)) obj)
    (assert (eql x p:fail))))

(let* ((str "ba")
       (obj (p:new str)))
  (mvbind (x rest) (funcall (p:other (p:char #\a)) obj)
    (assert (eql x #\b))
    (assert (equal rest (list 0 1 str)))))

; some tests for many
(let* ((str0 "aa")
       (str1 "abb")
       (obj (p:new str0 str1)))
  (mvbind (l rest) (funcall (p:many (p:char #\a)) obj)
    (assert (equal l '(#\a #\a #\a)))
    (assert (equal rest (list 1 1 str1)))))

(let* ((obj (p:new "bb")))
  (mvbind (l rest) (funcall (p:many (p:char #\a)) obj)
    ;(pprint rest)
    (assert (null l))
    ))

; some tests for many-till
(let* ((str (symbol-name 'not1-0))
       (obj (p:new str)))
  (mvbind (l rest)
          (funcall (p:many-till (p:satisfy (lambda (_) t))
                                (p:char #\-))
                   obj)
    (assert (equal l (coerce "NOT1-" 'list)))
    (assert (equal rest (list 0 5 str)))))

(let* ((str "-ab")
       (obj (p:new str)))
  (mvbind (l rest)
          (funcall (p:many-till (p:satisfy (lambda (_) t))
                                (p:char #\-))
                   obj)
    (assert (equal l (list #\-)))))

(let* ((str "ab")
       (obj (p:new str)))
  (mvbind (l rest)
          (funcall (p:many-till (p:satisfy (lambda (x)
                                             (not (eql x 'p:eof))))
                                (p:char #\-))
                   obj)
    (assert (eql l p:fail))))


(in-package p)

; some tests for peek and next
(let* ((str0 "ab")
       (str1 "c")
       (obj (new str0 str1)))
  (assert (equal obj
                 (list 0 0 str0 str1)))
  (assert (eql (peek obj) #\a))

  (setq obj (next obj))
  (assert (equal obj
                 (list 0 1 str0 str1)))
  (assert (eql (peek obj) #\b))

  (setq obj (next obj))
  (assert (equal obj
                 (list 1 0 str1)))
  (assert (eql (peek obj) #\c))

  (setq obj (next obj))
  (assert (equal obj
                 (list 2 0)))
  (assert (eql (peek obj) 'eof))

  (setq obj (next obj))
  (assert (equal obj
                 (list 2 0)))
  (assert (eql (peek obj) 'eof))
)

(let* ((str0 "")
       (str1 "a")
       (str2 "")
       (obj (new str0 str1 str2)))
  (assert (equal obj
                 (list 1 0 str1 str2)))
  (assert (eql (peek obj) #\a))

  (setq obj (next obj))
  (assert (equal obj
                 (list 3 0)))
  (assert (eql (peek obj) 'eof))
)
