dep: Major overhaul.
[lisp] / infix.lisp
index 5cdd0b9..a77f51e 100644 (file)
 ;;; it under the terms of the GNU General Public License as published by
 ;;; the Free Software Foundation; either version 2 of the License, or
 ;;; (at your option) any later version.
-;;; 
+;;;
 ;;; This program is distributed in the hope that it will be useful,
 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;;; GNU General Public License for more details.
-;;; 
+;;;
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with this program; if not, write to the Free Software Foundation,
 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -70,7 +70,7 @@
   (name nil :type symbol)
   (lprec nil :type (or fixnum null))
   (rprec nil :type (or fixnum null))
-  (func (lambda () nil) :type (function () t)))
+  (func (lambda () nil) :type #-ecl (function () t) #+ecl function))
 
 ;;;--------------------------------------------------------------------------
 ;;; Global parser state.
 ;;;--------------------------------------------------------------------------
 ;;; The tokenizer.
 
-(defconstant eof (cons :eof nil)
-  "A magical object which `get-token' returns at end-of-file.")
+(eval-when (:compile-toplevel :load-toplevel :execute)
+  (let ((value (cons :eof nil)))
+    (unless (and (boundp 'eof)
+                (equal (symbol-value 'eof) value))
+      (defconstant eof (cons :eof nil)
+       "A magical object which `get-token' returns at end-of-file."))))
 
 (defun default-get-token ()
   "Read a token from *stream* and store it in *token*."
   (pushval `(loop ,@(strip-progn (parse-infix 0)))))
 
 (defopfunc bind operand
-  (labels ((loop ()
+  (labels ((loopy ()
            (let ((ids (parse-ident-list))
                  (valform (progn (delim '=) (parse-infix 0)))
                  (body (if (delim '|,| nil)
-                           (loop)
+                           (loopy)
                            (progn
                              (delim 'in)
                              (strip-progn (parse-infix 0))))))
                        `(let ((,(car ids) ,valform)) ,@body)
                        `(multiple-value-bind ,ids ,valform ,@body))))))
     (get-token)
-    (pushval (car (loop)))))
+    (pushval (car (loopy)))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Parsing function bodies and lambda lists.
   (cond ((delim '|(| nil)
         (prog1 (parse-infix) (delim '|)|)))
        (t (prog1 *token* (get-token)))))
-        
+
 (defopfunc lambda operand
   (get-token)
   (pushval `(lambda ,(parse-lambda-list) ,@(strip-progn (parse-infix 0)))))
       (unless (eq *token* delim)
        (error "expected ~S; found ~S" delim *token*)))))
 
-(defun install-infix-reader (&optional (char #\$))
-  "Installs a macro character `$ INFIX...  $' for translating infix notation
+(defun install-infix-reader
+    (&optional (start #\{) (end #\}) &key dispatch (readtable *readtable*))
+  "Installs a macro character `{ INFIX... }' for translating infix notation
    to Lisp forms.  You also want to (use-package :infix-keywords) if you do
    this."
-  (let ((delim (intern (string #\$) 'infix-keywords)))
-    (set-macro-character char (lambda (stream ch)
-                               (declare (ignore ch))
-                               (read-infix stream :delim delim)))))
+  (let ((delim (intern (string end) 'infix-keywords)))
+    (flet ((doit (stream &rest noise)
+            (declare (ignore noise))
+            (read-infix stream :delim delim)))
+      (if dispatch
+         (set-dispatch-macro-character dispatch start #'doit readtable)
+         (set-macro-character start #'doit nil readtable))
+      (unless (or (eql start end)
+                 (multiple-value-bind
+                     (func nontermp)
+                     (get-macro-character end readtable)
+                   (and func (not nontermp))))
+       (set-macro-character end (lambda (noise)
+                                  (declare (ignore noise))
+                                  (error "Unexpected `~C'." end))
+                            nil readtable)))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Testing things.