diff options
-rw-r--r-- | src/lex.lisp | 22 | ||||
-rw-r--r-- | t/lex.lisp | 19 |
2 files changed, 39 insertions, 2 deletions
diff --git a/src/lex.lisp b/src/lex.lisp index c6e9cf7..e86d1e9 100644 --- a/src/lex.lisp +++ b/src/lex.lisp @@ -9,7 +9,7 @@ :reader instance)) (:report (lambda (condition stream) (format stream - "Lex failed--encountered ~a while reading ~a." + "LEX failed--encountered ~a while reading ~a." (chr condition) (instance condition)))) (:documentation "Dedicated error for immediates/keywords which contain invalid characters.")) @@ -63,6 +63,9 @@ Comments start with a semi-colon ';' and all tokens after are ignored." (t (error (format nil "~a is not a valid lexical symbol.~%" chr)))))) (defun read-immediate (chr) + "Reads a sequence of digits, in base 2, 8, 10, or 16.. Throws +`invalid-immediate-or-keyword' error if an alphabetic character is encountered." + ;; may be combined with read-keyword-helper (defun read-immediate-helper (chrs-so-far) (let ((chr (peek-char nil *standard-input* nil))) (cond ((and (not (null chr)) (digit-char-p chr)) @@ -70,9 +73,24 @@ Comments start with a semi-colon ';' and all tokens after are ignored." ((and (not (null chr)) (alpha-char-p chr)) (error 'invalid-immediate-or-keyword :chr chr :instance "immediate")) (t (reverse chrs-so-far))))) - (parse-integer (coerce (read-immediate-helper (list chr)) 'string))) + + (let* ((next (peek-char nil *standard-input* nil)) + (radix (cond ((null next) 10) + ((char= next #\b) 2) + ((char= next #\o) 8) + ((char= next #\x) 16) + ((digit-char-p next) 10) + (t nil))) + (arg (list chr))) + (when (and (char= chr #\0) radix (not (= radix 10))) + (read-char *standard-input* nil) + (setq arg '())) + (parse-integer (coerce (read-immediate-helper arg) 'string) :radix radix))) (defun read-keyword (chr) + "Reads a sequence of alphabetic characters. Throws `invalid-immediate-or-keyword' +error if a digit is encountered." + ;; may be combined with read-immediate-helper (defun read-keyword-helper (chrs-so-far) (let ((chr (peek-char nil *standard-input* nil))) (cond ((and (not (null chr)) (alpha-char-p chr)) @@ -52,12 +52,31 @@ (read-this "123456789" (is (= (lex:read-token) 123456789)))) +(test read-token-immediate-binary + (read-this "0b00101010" + (is (= (lex:read-token) 42)))) + +(test read-token-immediate-octal + (read-this "0o052" + (is (= (lex:read-token) 42)))) + +(test read-token-immediate-hexadecimal + (read-this "0x200" + (is (= (lex:read-token) 512)))) + (test read-token-immediate-invalid-immediate (handler-case (progn (read-this "0v0" (lex:read-token)) (fail)) (lex:invalid-immediate-or-keyword ()))) +;; do we want a custom error for this too? +(test read-token-immediate-radix + (handler-case + (progn (read-this "0x" (lex:read-token)) + (fail)) + (sb-int:simple-parse-error ()))) + (test read-token-keyword-single (read-this "a" (is (string= (lex:read-token) "a")))) |