chibi-scheme/tests/parse-tests.scm

115 lines
3.2 KiB
Scheme

(import (chibi) (chibi test)
(chibi char-set) (chibi char-set ascii)
(chibi parse))
(test-begin "parse")
;; basic
(test-assert (parse parse-epsilon ""))
(test-assert (parse-fully parse-epsilon ""))
(test-error (parse-fully parse-epsilon "a"))
(test-not (parse parse-anything ""))
(test-assert (parse-fully parse-anything "a"))
(test-error (parse-fully parse-anything "ab"))
(test-not (parse parse-nothing ""))
(test-not (parse parse-nothing "a"))
(test-not (parse (parse-char #\a) ""))
(test-assert (parse-fully (parse-char #\a) "a"))
(test-not (parse (parse-char #\a) "b"))
(test-error (parse-fully (parse-char #\a) "ab"))
(let ((f (parse-seq (parse-char #\a) (parse-char #\b))))
(test-not (parse f "a"))
(test-not (parse f "b"))
(test-assert (parse f "ab"))
(test-error (parse-fully f "abc")))
(let ((f (parse-or (parse-char #\a) (parse-char #\b))))
(test-not (parse f ""))
(test-assert (parse f "a"))
(test-assert (parse f "b"))
(test-error (parse-fully f "ab")))
(let ((f (parse-not (parse-char #\a))))
(test-assert (parse f ""))
(test-error (parse-fully f "a"))
(test-assert (parse f "b")))
(let ((f (parse-repeat (parse-char #\a))))
(test-assert (parse-fully f ""))
(test-assert (parse-fully f "a"))
(test-assert (parse-fully f "aa"))
(test-assert (parse-fully f "aaa"))
(test-assert (parse f "b"))
(test-assert (parse f "aab"))
(test-error (parse-fully f "aab")))
;; grammars
(let ()
(define-grammar calc
(space ((* ,char-set:whitespace)))
(number ((=> n (+ ,char-set:digit))
(string->number (list->string n))))
(simple ((=> n ,number) n)
((: "(" (=> e1 ,term) ")") e1))
(term-op ("*" *)
("/" /)
("%" modulo))
(term ((: (=> e1 ,simple) ,space (=> op ,term-op) ,space (=> e2 ,term))
(op e1 e2))
((=> e1 ,simple)
e1)))
(test 88 (parse term "4*22"))
(test 42 (parse term "42"))
;; partial match (grammar isn't checking end)
(test 42 (parse term "42*")))
(define calculator
(grammar expr
(space ((: ,char-set:whitespace ,space))
(() #f))
(digit ((=> d ,char-set:digit) d))
(number ((=> n (+ ,digit))
(string->number (list->string n))))
(simple ((=> n ,number) n)
((: "(" (=> e1 ,expr) ")") e1))
(term-op ("*" *)
("/" /)
("%" modulo))
(term ((: (=> e1 ,simple) ,space (=> op ,term-op) ,space (=> e2 ,term))
(op e1 e2))
((=> e1 ,simple)
e1))
(expr-op ("+" +) ("-" -))
(expr ((: ,space (=> e1 ,term) ,space (=> op ,expr-op) ,space (=> e2 ,expr))
(op e1 e2))
((: ,space (=> e1 ,term))
e1))))
(test 42 (parse calculator "42"))
(test 4 (parse calculator "2 + 2"))
(test 23 (parse calculator "2 + 2*10 + 1"))
(test 25 (parse calculator "2+2 * 10+1 * 3"))
(test 41 (parse calculator "(2 + 2) * 10 + 1"))
;; this takes exponential time without memoization
(define explode
(grammar start
(start ((: ,S eos) #t))
(S ((+ ,A) #t))
(A ((: "a" ,S "b") #t)
((: "a" ,S "c") #t)
((: "a") #t))))
(test-assert (parse explode "aaabb"))
(test-not (parse explode "bbaa"))
(test-assert
(parse explode (string-append (make-string 10 #\a) (make-string 8 #\c))))
(test-end)