(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-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))))