diff options
author | riton <riton@riton.home> | 2025-07-12 20:02:22 +0300 |
---|---|---|
committer | riton <riton@riton.home> | 2025-07-12 20:05:21 +0300 |
commit | 44efb492349025a195a3b402ec580623ad61723f (patch) | |
tree | a93f9693283598e5e3d85627624789ec136923c7 | |
parent | 8afcee0b1087dad6c821aa2ee1e917e3301f0e81 (diff) |
defined deftest macro
Squashed commit of the following:
commit b7779c8d9013d52f4fa94970ac7346ea619eb37c
Author: riton <riton@riton.home>
Date: Sat Jul 12 15:41:56 2025 +0300
shorthands for some of the test definition tokens
commit d37ba8faf43f3a8b54b88bc8df4ab2995935b782
Author: riton <riton@riton.home>
Date: Sat Jul 12 15:23:21 2025 +0300
run all tests
commit dfc1b2dfaeb50825b7d609ce6b27dc0f8818afb0
Author: riton <riton@riton.home>
Date: Sat Jul 12 14:55:44 2025 +0300
deftest macro
-rw-r--r-- | src/lexer-test.lisp | 189 | ||||
-rw-r--r-- | src/token.lisp | 2 |
2 files changed, 96 insertions, 95 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)) diff --git a/src/token.lisp b/src/token.lisp index f6536ac..8d37734 100644 --- a/src/token.lisp +++ b/src/token.lisp @@ -103,7 +103,7 @@ (defmethod print-object ((token token) stream) (print-unreadable-object (token stream :type t :identity t) - (princ (literal token) stream))) + (format stream "\"~a\"" (literal token)))) (defun as-token (token-type) (multiple-value-bind (str ok) (token->string token-type) |