chibi-scheme/lib/chibi/parse-test.sld

157 lines
5.5 KiB
Scheme

(define-library (chibi parse-test)
(export run-tests)
(import (scheme base) (scheme char)
(chibi test) (chibi parse) (chibi parse common))
(cond-expand
(chibi (import (chibi char-set) (chibi char-set ascii)))
(else (import (srfi 14))))
(begin
(define (run-tests)
(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-error (parse-fully parse-nothing ""))
(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")))
(let ((f (parse-seq (parse-char #\a)
(parse-ignore (parse-char #\b)))))
(test '(#\a) (parse f "ab")))
(let ((f (parse-seq (parse-char #\a)
(parse-ignore (parse-char #\b))
(parse-char #\c))))
(test '(#\a #\c) (parse f "abc")))
;; 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*")))
(let ()
(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")))
(let ()
(define prec-calc
(grammar expr
(simple (,(parse-integer))
((: "(" (=> e1 ,expr) ")") e1))
(op
("+" '+) ("-" '-) ("*" '*) ("/" '/) ("^" '^))
(expr
(,(parse-binary-op op
`((+ 5) (- 5) (* 3) (/ 3) (^ 1 right))
simple)))))
(test 42 (parse prec-calc "42"))
(test '(+ 2 2) (parse prec-calc "2 + 2"))
(test '(+ (+ 2 2) 2) (parse prec-calc "2 + 2 + 2"))
(test '(+ (+ 2 (* 2 10)) 1) (parse prec-calc "2 + 2*10 + 1"))
(test '(+ (+ 2 (* 2 10)) (* 1 3)) (parse prec-calc "2+2 * 10+1 * 3"))
(test '(+ (* (+ 2 2) 10) 1) (parse prec-calc "(2 + 2) * 10 + 1"))
(test '(^ 2 (^ 2 2)) (parse prec-calc "2 ^ 2 ^ 2"))
(test '(+ (+ (+ 1 (* (* 2 (^ 3 (^ 4 5))) 6)) (^ 7 8)) 9)
(parse prec-calc "1 + 2 * 3 ^ 4 ^ 5 * 6 + 7 ^ 8 + 9")))
;; this takes exponential time without memoization
(let ()
(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))))