diff options
Diffstat (limited to 'src/lexer-test.lisp')
-rw-r--r-- | src/lexer-test.lisp | 189 |
1 files changed, 95 insertions, 94 deletions
diff --git a/src/lexer-test.lisp b/src/lexer-test.lisp index 916af29..c6f131a 100644 --- a/src/lexer-test.lisp +++ b/src/lexer-test.lisp @@ -1,32 +1,79 @@ (in-package :monkey) -(defun make-tokens (&rest tokens) - (loop :for token :in tokens - :if (consp token) - :collect (make-token (car token) (cadr token)) - :if (typep token 'token-type) - :collect (as-token token))) +(defparameter *tests* (make-hash-table)) +(defparameter *test-name* nil) -(defun test-lexer (str expect) - (let ((lexer (make-lexer str))) - (not (find nil (mapcar #'token= (lexer-tokens lexer) expect))))) +(eval-always + (defun make-tokens (&rest tokens) + (loop :for token :in tokens + :if (consp token) + :collect (make-token (car token) (cadr token)) + :if (typep token 'token-type) + :collect (as-token token))) + (defun test-lexer (str expected-tokens) + (labels ((expected-next () + (prog1 (car expected-tokens) + (setf expected-tokens (cdr expected-tokens))))) + (format t "Testing ~s..." *test-name*) + (let* ((lexer (make-lexer str)) + (tokens (lexer-tokens lexer)) + (expected-token (expected-next)) + (ok t)) + (loop :for token :in tokens + :for i :from 1 + :if (not (token= token expected-token)) + :do (format t "~&token ~d: expected ~a but got ~a~%" i expected-token token) + (setf ok nil) + :else :do (setf expected-token (expected-next))) + (unless (null ok) + (format t " ok~%"))))) -(defun test-1 () - (test-lexer "=+(){},;" - (make-tokens :t/= - :t/+ - :t/lparen - :t/rparen - :t/lbrace - :t/rbrace - :t/comma - :t/semicolon - :t/eof))) + (defun tokenize (designator) + (cond ((typep designator 'token-type) + (as-token designator)) + ((stringp designator) + (make-token :t/ident designator)) + ((integerp designator) + (make-token :t/int (princ-to-string designator))) + ((characterp designator) + (case designator + (#\( (as-token :t/lparen)) + (#\) (as-token :t/rparen)) + (#\; (as-token :t/semicolon)) + (#\{ (as-token :t/lbrace)) + (#\} (as-token :t/rbrace)))) + ((consp designator) + (apply #'make-token designator)))) + (defun define-lexer-test (name string tokens) + `(progn + (setf (gethash ',name *tests*) t) + (defun ,name () + (let ((*test-name* ',name)) + (test-lexer ,string (list ,@(mapcar (lambda (tok) `(tokenize ',tok)) + tokens))))))) -(defun test-2 () - (test-lexer "let five = 5; + (defmacro deftest ((type &optional name) &body args) + (case type + (:lexer (apply #'define-lexer-test + (or name (gensym "LEXER-TEST")) + args))))) + +(defun run-tests () + (let ((ok t) key val) + (with-hash-table-iterator (it *tests*) + (loop :do (multiple-value-setq (ok key val) (it)) + :while ok + :do (funcall (symbol-function key)))))) + +(deftest (:lexer test-1) + "=+(){},;" + (:t/= :t/+ :t/lparen :t/rparen + :t/lbrace :t/rbrace :t/comma :t/semicolon :t/eof)) + +(deftest (:lexer test-2) + "let five = 5; let ten = 10; let add = fn(x, y) { @@ -45,75 +92,29 @@ if (5 < 10) { 10 == 10; 10 != 9; " - (make-tokens :t/let - (list :t/ident "five") - :t/= - (list :t/int "5") - :t/semicolon - :t/let - (list :t/ident "ten") - :t/= - (list :t/int "10") - :t/semicolon - :t/let - (list :t/ident "add") - :t/= - :t/function - :t/lparen - (list :t/ident "x") - :t/comma - (list :t/ident "y") - :t/rparen - :t/lbrace - (list :t/ident "x") - :t/+ - (list :t/ident "y") - :t/rbrace - :t/semicolon - :t/let - (list :t/ident "result") - :t/= - (list :t/ident "add") - :t/lparen - (list :t/ident "five") - :t/comma - (list :t/ident "ten") - :t/rparen - :t/semicolon - :t/! - :t/- - :t// - :t/* - :t/semicolon - (list :t/int "5") - :t/< - (list :t/int "10") - :t/> - (list :t/int "5") - :t/semicolon - (list :t/if "if") - :t/lparen - (list :t/int "5") - :t/< - (list :t/int "10") - :t/rparen - :t/lbrace - :t/return - :t/true - :t/semicolon - :t/rbrace - :t/else - :t/lbrace - :t/return - :t/false - :t/semicolon - :t/rbrace - (list :t/int "10") - :t/== - (list :t/int "10") - :t/semicolon - (list :t/int "10") - :t/!= - (list :t/int "9") - :t/semicolon - :t/eof ""))) + (:t/let "five" :t/= 5 #\; + :t/let "ten" :t/= 10 #\; + :t/let "add" :t/= :t/function #\( "x" :t/comma "y" #\) #\{ + "x" :t/+ "y" #\; + #\} #\; + :t/let "result" :t/= "add" #\( "five" :t/comma "ten" #\) #\; + :t/! :t/- :t// :t/* #\; + 5 :t/< 10 :t/> 5 #\; + :t/if #\( 5 :t/< 10 #\) #\{ + :t/return :t/true #\; + #\} :t/else #\{ + :t/return :t/false #\; + #\} + 10 :t/== 10 #\; + 10 :t/!= 9 #\; + :t/eof)) + + +(deftest (:lexer test-fail) + "abc gf 5 fn =+(){},;" + (:t/= :t/+ :t/lparen :t/rparen + :t/lbrace :t/rbrace :t/comma :t/semicolon :t/eof)) + +(deftest (:lexer test-fail-2) + "let abc x + 5;" + (:t/let "abc" :t/= "x" :t/+ 5 :t/eof)) |