chibi-scheme/tests/parse-tests.scm
Alex Shinn 8b5eb68238 File descriptors maintain a reference count of ports open on them
They can be close()d explicitly with close-file-descriptor, and
will close() on gc, but only explicitly closing the last port on
them will close the fileno.  Notably needed for network sockets
where we open separate input and output ports on the same socket.
2014-02-20 22:32:50 +09:00

134 lines
4 KiB
Scheme

(import (chibi) (chibi test)
(chibi char-set) (chibi char-set ascii)
(chibi parse) (chibi parse common))
(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"))
(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
(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)