;; Customizable, Common Lisp like reader for Emacs Lisp.
;; 
;; Copyright (C) 1993 by Guido Bosch <Guido.Bosch@loria.fr>

;; This file is written in GNU Emacs Lisp, but not (yet) part of GNU Emacs.

;; The software contained in this file is free software; you can
;; redistribute it and/or modify it under the terms of the GNU General
;; Public License as published by the Free Software Foundation; either
;; version 2, or (at your option) any later version.

;; GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;; 
;; Please send bugs and comments to the author.
;;
;; <DISCLAIMER>
;; This program is still under development.  Neither the author nor
;; his employer accepts responsibility to anyone for the consequences of
;; using it or for whether it serves any particular purpose or works
;; at all.


;; Introduction
;; ------------
;;
;; This package replaces the standard Emacs Lisp reader (implemented
;; as a set of built-in Lisp function in C) by a flexible and
;; customizable Common Lisp like one (implemented entirely in Emacs
;; Lisp). During reading of Emacs Lisp source files, it is about 40%
;; slower than the built-in reader, but there is no difference in
;; loading byte compiled files - they dont contain any syntactic sugar
;; and are loaded with the built in subroutine `load'.
;;
;; The user level functions for defining read tables, character and
;; dispatch macros are implemented according to the Commom Lisp
;; specification by Steel's (2nd edition), but the read macro functions
;; themselves are implemented in a slightly different way, because the
;; basic character reading is done in an Emacs buffer, and not by
;; using the primitive functions `read-char' and `unread-char', as real
;; CL does.  To get 100% compatibility with CL, the above functions
;; (or their equivalents) must be implemented as subroutines.
;;
;; Another difference with real CL reading is that basic tokens (symbols
;; numbers, strings, and a few more) are still read by the original
;; built-in reader. This is necessary to get reasonable performance.
;; As a consquence, the read syntax of basic tokens can't be
;; customized.

;; Most of the built-in reader syntax has been replaced by lisp
;; character macros: parentheses and brackets, simple and double
;; quotes, semicolon comments and the dot. In addition to that, the
;; following new syntax features are provided:

;; Backquote-Comma-Atsign Macro: `(,el ,@list) 
;;
;; (the clumsy Emacs Lisp syntax (` ((, el) (,@ list))) is also
;; supported, but with one restriction: the blank behind the quote
;; characters is mandatory when using the old syntax. The cl reader
;; needs it as a landmark to distinguish between old and new syntax.
;; An example:
;;
;; With blanks, both readers read the same:
;; (` (, (head)) (,@ (tail))) -std-read->  (` (, (head)) (,@ (tail)))
;; (` (, (head)) (,@ (tail))) -cl-read->   (` (, (head)) (,@ (tail)))
;;
;; Without blanks, the form is interpreted differently by the two readers:
;; (`(,(head)) (,@(tail))) -std-read-> (` (, (head)) (,@ (tail)))
;; (`(,(head)) (,@(tail))) -cl-read->  ((` ((, ((head)))) ((,@ ((tail)))))
;;
;; 
;; Dispatch Character Macro" `#'
;;
;; #'<function>			function quoting
;; #\<charcter>			character syntax
;; #.<form>    			read time evaluation
;; #p<path>, #P<path> 		paths
;; #+<feature>, #-<feature> 	conditional reading
;; #<n>=, #<n># 		tags for shared structure reading
;;
;; Other read macros can be added easily (see the definition of the
;; above ones in this file, using the functions `set-macro-character'
;; and `set-dispatch-macro-character')
;;
;; The Cl reader is mostly downward compatile, (exception: backquote
;; comma macro, see above). E.g., this file, which is written entirely
;; in the standard Emacs Lisp syntax, can be read and compiled with the
;; cl-reader activated (see Examples below). 

;; This also works with package.el for Common Lisp packages.


;; Requirements
;; ------------
;; The package runs on Emacs 18 and Emacs 19 (FSF and Lucid) It is
;; built on top of Dave Gillespie's cl.el package (version 2.02 or
;; later).  The old one (from Ceazar Quiroz, still shiped with some
;; Emacs 19 disributions) will not do.

;; Usage
;; -----
;; The package is implemented as a kind of minor mode to the
;; emacs-lisp-mode. As most of the Emacs Lisp files are still written
;; in the standard Emacs Lisp syntax, the cl reader is only activated
;; on elisp files whose property lines contain the following entry:
;;
;; -*- Read-Syntax: Common-Lisp -*-
;;
;; Note that both property name ("Read-Syntax") and value
;; ("Common-Lisp") are not case sensitive. There can also be other
;; properties in this line: 
;;
;; -*- Mode: Emacs-Lisp; Read-Syntax: Common-Lisp -*-

;; Installation
;; ------------
;; Save this file in a directory where Emacs will find it, then
;; byte compile it (M-x byte-compile-file).
;;
;; A permanent installation of the package can be done in two ways:
;;
;; 1.) If you want to have the package always loaded, put this in your
;;     .emacs, or in just the files that require it:
;;
;; (require 'cl-read) 
;;
;; 2.) To load the cl-read package automatically when visiting an elisp
;;     file that needs it, it has to be installed using the
;;     emacs-lisp-mode-hook. In this case, put the following function
;;     definition and add-hook form in your .emacs:
;;
;; (defun cl-reader-autoinstall-function () 
;;   "Activates the Common Lisp style reader for emacs-lisp-mode buffers,
;; if the property line has a local variable setting like this: 
;; \;\; -*- Read-Syntax: Common-Lisp -*-"
;;
;;   (or (boundp 'local-variable-hack-done)
;;       (let (local-variable-hack-done
;;             (case-fold-search t))
;;         (hack-local-variables-prop-line 't)
;;         (cond 
;;          ((and (boundp 'read-syntax)
;;                read-syntax
;;                (string-match "^common-lisp$" (symbol-name read-syntax)))
;;           (require 'cl-read)
;;           (make-local-variable 'cl-read-active)
;;           (setq cl-read-active 't))))))
;;
;; (add-hook 'emacs-lisp-mode-hook 'cl-reader-autoinstall-function)
;;
;; The `cl-reader-autoinstall-function' function tests for the
;; presence of the correct Read-Syntax property in the first line of
;; the file and loads the cl-read package if necessary. cl-read
;; replaces the following standard elisp functions:
;;
;; 	- read
;; 	- read-from-string
;; 	- eval-current-buffer
;; 	- eval-buffer
;; 	- eval-region
;;	- eval-expression (to call reader explicitly)
;;
;; There may be other built-in functions that need to be replaced
;; (e.g. load).  The behavior of the new reader function depends on
;; the value of the buffer local variable `cl-read-active': if it is
;; nil, they just call the original functions, otherwise they call the
;; cl reader. If the cl reader is active in a buffer, this is
;; indicated in the modeline by the string "CL" (minor mode like). 
;;

;; Examples:
;; ---------
;; After having installed the package as described above, the
;; following forms can be evaluated (M-C-x) with the cl reader being
;; active. (make sure that the mode line displays "(Emacs-Lisp CL)")
;;
;; (setq whitespaces '(#\space #\newline #\tab))
;; (setq more-whitespaces `(#\page ,@whitespaces #\linefeed))
;; (setq whitespace-strings (mapcar #'char-to-string more-whitespaces))
;; 
;; (setq shared-struct '(#1=[hello world] #1# #1#))
;; (progn (setq cirlist '#1=(a b . #1#)) 't)
;;
;; This file, though written in standard Emacs Lisp syntax, can also be
;; compiled with the cl reader active: Type M-x byte-compile-file

;; TO DO List: 
;; -----------
;; - Provide a replacement for load so that uncompiled cl syntax
;;   source file can be loaded, too.  For now prohibit loading un-bytecompiled.
;; - Do we really need the (require 'cl) dependency?   Yes.
;; - More read macros: #S for structs, #A for array, #X for hex, #nR for radix
;; - Refine the error signaling mechanism.
;;     - invalid-cl-read-syntax is now defined. what else?


; Change History
; 
; $Log:	cl-read.el,v $
; Revision 1.19  94/03/21  19:59:24  liberte
; Add invalid-cl-read-syntax error symbol.
; Add reader::read-sexp and reader::read-sexp-func to allow customization
; based on the results of reading.
; Remove more dependencies on cl-package.
; Remove reader::eval-current-buffer, eval-buffer, and eval-region,
; and use elisp-eval-region package instead.
; 
; Revision 1.18  94/03/04  23:42:24  liberte
; Fix typos in comments.
; 
; Revision 1.17  93/11/24  12:04:09  bosch
; cl-packages dependency removed. `reader::read-constituent' and
; corresponding variables moved to cl-packages.el.
; Multi-line comment #| ... |# dispatch character read macro added.
; 
; Revision 1.16  1993/11/23  10:21:02  bosch
; Patches from Daniel LaLiberte integrated.
;
; Revision 1.15  1993/11/18  21:21:10  bosch
; `reader::symbol-regexp1' modified.
;
; Revision 1.14  1993/11/17  19:06:32  bosch
; More characters added to `reader::symbol-characters'.
; `reader::read-constituent' modified.
; defpackage form added.
;
; Revision 1.13  1993/11/16  13:06:41  bosch
; - Symbol reading for CL package convention implemented.
;   Variables `reader::symbol-characters', `reader::symbol-regexp1' and
;   `reader::symbol-regexp2' and functions `reader::lookup-symbol' and
;   `reader::read-constituent' added.
; - Prefix for internal symbols is now "reader::" (Common Lisp
;   compatible).
; - Dispatch character macro #: for reading uninterned symbols added.
;
; Revision 1.12  1993/11/07  19:29:07  bosch
; Minor bug fix.
;
; Revision 1.11  1993/11/07  19:23:59  bosch
; Comment added. Character read macro #\<char> rewritten. Now reads 
; e.g. #\meta-control-x. Needs to be checked. 
; fix in `reader::restore-shared-structure'. `cl-reader-autoinstall-function' improved.
;
; Revision 1.10  1993/11/06  18:35:35  bosch
; Included Daniel LaLiberte's Patches.
; Efficiency of `reader::restore-shared-structure' improved.
; Implementation notes for shared structure reading added.
;
; Revision 1.9  1993/09/08  07:44:54  bosch
; Comment modified.
;
; Revision 1.8  1993/08/10  13:43:34  bosch
; Hook function `cl-reader-autoinstall-function' for automatic installation added.
; Buffer local variable `cl-read-active' added: together with the above
; hook it allows the file specific activation of the cl reader.
;
; Revision 1.7  1993/08/10  10:35:21  bosch
; Functions `read*' and `read-from-string*' renamed into `reader::read'
; and `reader::read-from-string'. Whitespace character skipping after
; recursive reader calls removed (Emacs 19 should not need this).
; Functions `cl-reader-install'  and `cl-reader-uninstall' updated.
; Introduction text and  function comments added.
;
; Revision 1.6 1993/08/09 15:36:05 bosch Function `read*' now nearly
; elisp compatible (no functions as streams, yet -- I don't think I
; will ever implement this, it would be far too slow).  Elisp
; compatible function `read-from-string*' added.  Replacements for
; `eval-current-buffer', `eval-buffer' and `eval-region' added.
; Renamed feature `cl-dg' in `cl', as Dave Gillespie's cl.el package
; is rather stable now.  Function `cl-reader-install' and
; `cl-reader-uninstall' modified.
;
; Revision 1.5  1993/08/09  10:23:35  bosch
; Functions `copy-readtable' and `set-syntax-from-character' added.
; Variable `reader::internal-standard-readtable' added.  Standard
; readtable initialization modified. Whitespace skipping placed back
; inside the read loop.
;
; Revision 1.4  1993/05/14  13:00:48  bosch
; Included patches from Daniel LaLiberte.
;
; Revision 1.3  1993/05/11  09:57:39  bosch
; `read*' renamed in `reader::read-from-buffer'. `read*' now can read
; from strings.
;
; Revision 1.2  1993/05/09  16:30:50  bosch
; (require 'cl-read) added.
; Calling of `{before,after}-read-hook' modified.
;
; Revision 1.1  1993/03/29  19:37:21  bosch
; Initial revision
;
;

;; 
(require 'cl)

(provide 'cl-read)
;; load before compiling
(require 'cl-read)

;; bootstrapping with cl-packages
;; defpackage and in-package are ignored until cl-read is installed.
'(defpackage reader
  (:nicknames "rd")
  (:use el)
  (:export
   cl-read-active
   copy-readtable
   set-macro-character
   get-macro-character
   set-syntax-from-character
   make-dispatch-macro-character
   set-dispatch-macro-character
   get-dispatch-macro-character
   before-read-hook
   after-read-hook
   cl-reader-install
   cl-reader-uninstall
   read-syntax
   cl-reader-autoinstall-function))

'(in-package reader)


(autoload 'compiled-function-p "bytecomp")

;; This makes cl-read behave as a kind of minor mode: 

(make-variable-buffer-local 'cl-read-active)
(defvar cl-read-active nil
  "Buffer local variable that enables Common Lisp style syntax reading.")
(setq-default cl-read-active nil)

(or (assq 'cl-read-active minor-mode-alist)
    (setq minor-mode-alist
	  (cons '(cl-read-active " CL") minor-mode-alist)))

;; Define a new error symbol: invalid-cl-read-syntax
;; XEmacs change
(define-error 'invalid-cl-read-syntax "Invalid CL read syntax"
  'invalid-read-syntax)

(defun reader::error (msg &rest args)
  (signal 'invalid-cl-read-syntax (list (apply 'format msg args))))


;; The readtable

(defvar reader::readtable-size 256
  "The size of a readtable."
  ;; Actually, the readtable is a vector of size (1+
  ;; reader::readtable-size), because the last element contains the
  ;; symbol `readtable', used for defining `readtablep.
  )

;; An entry of the readtable must have one of the following forms:
;;
;; 1. A symbol, one of {illegal, constituent, whitespace}.  It means 
;;    the character's reader class.
;;
;; 2. A function (i.e., a symbol with a function definition, a byte
;;    compiled function or an uncompiled lambda expression).  It means the
;;    character is a macro character.
;;
;; 3. A vector of length `reader::readtable-size'. Elements of this vector
;;    may be `nil' or a function (see 2.). It means the charater is a
;;    dispatch character, and the vector its dispatch fucntion table.

(defvar *readtable*)
(defvar reader::internal-standard-readtable)

(defun* copy-readtable 
    (&optional (from-readtable *readtable*) 
	       (to-readtable 
		(make-vector (1+ reader::readtable-size) 'illegal)))
  "Return a copy of FROM-READTABLE \(default: *readtable*\). If the
FROM-READTABLE argument is provided as `nil', make a copy of a
standard \(CL-like\) readtable. If TO-READTABLE is provided, modify and
return it, otherwise create a new readtable object."

  (if (null from-readtable)
      (setq from-readtable reader::internal-standard-readtable))

  (loop for i to reader::readtable-size
	as from-syntax = (aref from-readtable i)
	do (setf (aref to-readtable i)
		 (if (vectorp from-syntax)
		     (copy-sequence from-syntax)
		   from-syntax))
	finally return to-readtable))


(defmacro reader::get-readtable-entry (char readtable)
  (` (aref (, readtable) (, char))))
   
(defun set-macro-character 
  (char function &optional readtable)
    "Makes CHAR to be a macro character with FUNCTION as handler.
When CHAR is seen by reader::read-from-buffer, it calls FUNCTION.
Returns always t. Optional argument READTABLE is the readtable to set
the macro character in (default: *readtable*)."
  (or readtable (setq readtable *readtable*))
  (or (reader::functionp function) 
      (reader::error "Not valid character macro function: %s" function)) 
  (setf (reader::get-readtable-entry char readtable) function)
  t)


(put 'set-macro-character 'edebug-form-spec 
     '(&define sexp function-form &optional sexp))
(put 'set-macro-character 'lisp-indent-function 1)

(defun get-macro-character (char &optional readtable)
   "Return the function associated with the character CHAR.
Optional READTABLE defaults to *readtable*. If char isn't a macro
character in READTABLE, return nil."
   (or readtable (setq readtable *readtable*))
   (let ((entry (reader::get-readtable-entry char readtable)))
     (if (reader::functionp entry) 
	 entry)))

(defun set-syntax-from-character 
  (to-char from-char &optional to-readtable from-readtable)   
  "Make the syntax of TO-CHAR be the same as the syntax of FROM-CHAR.
Optional TO-READTABLE and FROM-READTABLE are the corresponding tables
to use. TO-READTABLE defaults to the current readtable
\(*readtable*\), and FROM-READTABLE to nil, meaning to use the
syntaxes from the standard Lisp Readtable."
  (or to-readtable (setq to-readtable *readtable*))
  (or from-readtable 
      (setq from-readtable reader::internal-standard-readtable))
  (let ((from-syntax
	 (reader::get-readtable-entry from-char from-readtable)))
    (if (vectorp from-syntax)
	;; dispatch macro character table
	(setq from-syntax (copy-sequence from-syntax)))
    (setf (reader::get-readtable-entry to-char to-readtable)
	  from-syntax))
  t)


;; Dispatch macro character
(defun make-dispatch-macro-character (char &optional readtable)
  "Let CHAR be a dispatch macro character in READTABLE (default: *readtable*)."
  (or readtable (setq readtable *readtable*))
  (setf (reader::get-readtable-entry char readtable)
	;; create a dispatch character table 
	(make-vector reader::readtable-size nil)))


(defun set-dispatch-macro-character 
  (disp-char sub-char function &optional readtable)
  "Make reading CHAR1 followed by CHAR2 be handled by FUNCTION.
Optional argument READTABLE (default: *readtable*).  CHAR1 must first be 
made a dispatch char with `make-dispatch-macro-character'."
  (or readtable (setq readtable *readtable*))
  (let ((disp-table (reader::get-readtable-entry disp-char readtable)))
    ;; check whether disp-char is a valid dispatch character
    (or (vectorp disp-table)
	(reader::error "`%c' not a dispatch macro character." disp-char))
    ;; check whether function is a valid function 
    (or (reader::functionp function) 
	(reader::error "Not valid dispatch character macro function: %s" 
		       function))
    (setf (aref disp-table sub-char) function)))

(put 'set-dispatch-macro-character 'edebug-form-spec
     '(&define sexp sexp function-form &optional sexp))
(put 'set-dispatch-macro-character 'lisp-indent-function 2)


(defun get-dispatch-macro-character 
  (disp-char sub-char &optional readtable)
  "Return the macro character function for SUB-CHAR unser DISP-CHAR.
Optional READTABLE defaults to *readtable*.
Returns nil if there is no such function."
  (or readtable (setq readtable *readtable*))
  (let ((disp-table (reader::get-readtable-entry disp-char readtable)))
    (and (vectorp disp-table)
	 (reader::functionp (aref disp-table sub-char))
	 (aref disp-table sub-char))))


(defun reader::functionp (function)
  ;; Check whether FUNCTION is a valid function object to be used 
  ;; as (dispatch) macro character function.
  (or (and (symbolp function) (fboundp function))
      (compiled-function-p function)
      (and (consp function) (eq (first function) 'lambda))))
	   

;; The basic reader loop 

;; shared and circular structure reading
(defvar reader::shared-structure-references nil)
(defvar reader::shared-structure-labels nil)

(defun reader::read-sexp-func (point func)
  ;; This function is called to read a sexp at POINT by calling FUNC.
  ;; reader::read-sexp-func is here to be advised, e.g. by Edebug,
  ;; to do something before or after reading.
  (funcall func))

(defmacro reader::read-sexp (point &rest body)
  ;; Called to return a sexp starting at POINT.  BODY creates the sexp result
  ;; and should leave point after the sexp.  The body is wrapped in
  ;; a lambda expression and passed to reader::read-sexp-func.
  (` (reader::read-sexp-func (, point) (function (lambda () (,@ body))))))

(put 'reader::read-sexp 'edebug-form-spec '(form body))
(put 'reader::read-sexp 'lisp-indent-function 2)
(put 'reader::read-sexp 'lisp-indent-hook 1)  ;; Emacs 18


(defconst before-read-hook nil)
(defconst after-read-hook nil)

;; Set the hooks to `read-char' in order to step through the reader. e.g.
;; (add-hook 'before-read-hook '(lambda () (message "before") (read-char)))
;; (add-hook 'after-read-hook '(lambda () (message "after") (read-char)))

(defmacro reader::encapsulate-recursive-call (reader-call)
  ;; Encapsulate READER-CALL, a form that contains a recursive call to
  ;; the reader, for usage inside the main reader loop.  The macro
  ;; wraps two hooks around READER-CALL: `before-read-hook' and
  ;; `after-read-hook'.
  ;;
  ;; If READER-CALL returns normally, the macro exits immediately from
  ;; the surrounding loop with the value of READER-CALL as result.  If
  ;; it exits non-locally (with tag `reader-ignore'), it just returns
  ;; the value of READER-CALL, in which case the surrounding reader
  ;; loop continues its execution.
  ;;
  ;; In both cases, `before-read-hook' and `after-read-hook' are
  ;; called before and after executing READER-CALL.
  ;; Are there any other uses for these hooks?  Edebug doesn't need them.
  (` (prog2
	 (run-hooks 'before-read-hook)
	 ;; this catch allows to ignore the return, in the case that
	 ;; reader::read-from-buffer should continue looping (e.g.
	 ;; skipping over comments)
	 (catch 'reader-ignore
	   ;; this only works inside a block (e.g., in a loop): 
	   ;; go outside 
	   (return 
	    (prog1 
		(, reader-call)
	      ;; this occurrence of the after hook fires if the 
	      ;; reader-call returns normally ...
	      (run-hooks 'after-read-hook))))
       ;; ... and that one if  it was thrown to the tag 'reader-ignore
       (run-hooks 'after-read-hook))))

(put 'reader::encapsulate-recursive-call 'edebug-form-spec '(form))
(put 'reader::encapsulate-recursive-call 'lisp-indent-function 0)

(defun reader::read-from-buffer (&optional stream reader::recursive-p)
  (or (bufferp stream)
      (reader::error "Sorry, can only read on buffers"))
  (if (not reader::recursive-p)
      ;; set up environment for shared structure reading
      (let (reader::shared-structure-references
	    reader::shared-structure-labels
	    tmp-sexp)
	;; the reader returns an unshared sexpr, possibly containing
	;; symbolic references
	(setq tmp-sexp (reader::read-from-buffer stream 't))
	(if ;; sexpr actually contained shared structures
	    reader::shared-structure-references
	    (reader::restore-shared-structure tmp-sexp)
	  ;; it did not, so don't bother about restoring
	  tmp-sexp))

    (loop for char = (following-char)
	  for entry = (reader::get-readtable-entry  char *readtable*)
	  if (eobp) do (reader::error "End of file during reading")
	  do 
	  (cond 

	   ((eq entry 'illegal)
	    (reader::error "`%c' has illegal character syntax" char))

	   ;; skipping whitespace characters must be done inside this
	   ;; loop as character macro subroutines may return without
	   ;; leaving the loop using (throw 'reader-ignore ...)
	   ((eq entry 'whitespace)
	    (forward-char 1)  
	    ;; skip all whitespace
	    (while (eq 'whitespace 
		       (reader::get-readtable-entry  
			(following-char) *readtable*))
	      (forward-char 1)))

	   ;; for every token starting with a constituent character
	   ;; call the built-in reader (symbols, numbers, strings,
	   ;; characters with ?<char> syntax)
	   ((eq entry 'constituent)    
	    (reader::encapsulate-recursive-call
	     (reader::read-constituent stream)))

	   ((vectorp entry)
	    ;; Dispatch macro character. The dispatch macro character
	    ;; function is contained in the vector `entry', at the
	    ;; place indicated by <sub-char>, the first non-digit
	    ;; character following the <disp-char>:
	    ;; 	<disp-char><digit>*<sub-char>
	    (reader::encapsulate-recursive-call
	      (loop initially do (forward-char 1)
		    for sub-char = (prog1 (following-char) 
				     (forward-char 1))
		    while (memq sub-char 
				'(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
		    collect sub-char into digit-args
		    finally 
		    (return 
		     (funcall 
		      ;; no test is done here whether a non-nil
		      ;; contents is a correct dispatch character
		      ;; function to apply.
		      (or (aref entry sub-char)
			  (reader::error
			   "Undefined subsequent dispatch character `%c'" 
			   sub-char))
		      stream
		      sub-char 
		      (string-to-int
		       (apply 'concat 
			      (mapcar 
			       'char-to-string digit-args))))))))
	    
	   (t
	    ;; must be a macro character. In this case, `entry' is
	    ;; the function to be called
	    (reader::encapsulate-recursive-call
	      (progn 
		(forward-char 1)
		(funcall entry stream char))))))))


;; Constituent reader fix for Emacs 18
(if (string-match "^19" emacs-version)
    (defun reader::read-constituent (stream)
      (reader::read-sexp (point)
	(reader::original-read stream)))

  (defun reader::read-constituent (stream)
    (reader::read-sexp (point)
      (prog1 (reader::original-read stream)
	;; For Emacs 18, backing up is necessary because the `read' function 
	;; reads one character too far after reading a symbol or number.
	;; This doesnt apply to reading chars (e.g. ?n).
	;; This still loses for escaped chars.
	(if (not (eq (reader::get-readtable-entry
		      (preceding-char) *readtable*) 'constituent))
	    (forward-char -1))))))


;; Make the default current CL readtable

(defconst *readtable*
  (loop with raw-readtable = 
	(make-vector (1+ reader::readtable-size) 'illegal)
	initially do (setf (aref raw-readtable reader::readtable-size)
			   'readtable)
	for entry in 
	'((constituent ?! ?@ ?$ ?% ?& ?* ?_ ?- ?+ ?= ?/ ?\\ ?0 ?1 ?2
		       ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?: ?~ ?> ?< ?a ?b
		       ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p
		       ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?A ?B ?C ?D
		       ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R
		       ?S ?T ?U ?V ?W ?X ?Y ?Z)
	  (whitespace ?  ?\t ?\n ?\r ?\f)

	  ;; The following CL character classes are only useful for
	  ;; token parsing.  We don't need them, as token parsing is
	  ;; left to the built-in reader.
	  ;; (single-escape ?\\)
	  ;; (multiple-escape ?|)
	  )
	do 
	(loop for char in (rest entry)
	      do (setf (reader::get-readtable-entry  char raw-readtable)
		       (first entry)))
	finally return raw-readtable)
  "The current readtable.")


;; Variables used non-locally in the standard readmacros
(defvar reader::context)
(defvar reader::stack)
(defvar reader::recursive-p)


;;;; Read macro character definitions

;;; Hint for modifying, testing and debugging new read macros: All the
;;; read macros and dispatch character macros below are defined in
;;; the `*readtable*'.  Modifications or
;;; instrumenting with edebug are effective immediately without having to
;;; copy the internal readtable to the standard *readtable*.  However,
;;; if you wish to modify reader::internal-standard-readtable, then
;;; you must recopy *readtable*.

;; Chars and strings

;; This is defined to distinguish chars from constituents 
;; since chars are read by the standard reader without reading too far.
(set-macro-character ?\?
  (function
   (lambda (stream char)
     (forward-char -1)
     (reader::read-sexp (point)
       (reader::original-read stream)))))

;; ?\M-\C-a

;; This is defined to distinguish strings from constituents
;; since backing up after reading a string is simpler.
(set-macro-character ?\"
  (function
   (lambda (stream char)
     (forward-char -1)
     (reader::read-sexp (point)
       (prog1 (reader::original-read stream)
	 ;; This is not needed with Emacs 19, but it is OK.  See above.
	 (if (/= (preceding-char) ?\")
	     (forward-char -1)))))))

;; Lists and dotted pairs
(set-macro-character ?\( 
  (function 
   (lambda (stream char)
     (reader::read-sexp (1- (point))
       (catch 'read-list
	 (let ((reader::context 'list) reader::stack )
	   ;; read list elements up to a `.'
	   (catch 'dotted-pair
	     (while t
	       (setq reader::stack (cons (reader::read-from-buffer stream 't) 
					 reader::stack))))
	   ;; In dotted pair. Read one more element
	   (setq reader::stack (cons (reader::read-from-buffer stream 't) 
				     reader::stack)
		 ;; signal it to the closing paren
		 reader::context 'dotted-pair)
	   ;; Next char *must* be the closing paren that throws read-list
	   (reader::read-from-buffer stream 't)
	   ;; otherwise an error is signalled
	   (reader::error "Illegal dotted pair read syntax")))))))

(set-macro-character ?\) 
  (function 
   (lambda (stream char)
     (cond ((eq reader::context 'list)
	    (throw 'read-list (nreverse reader::stack)))
	   ((eq reader::context 'dotted-pair)
	    (throw 'read-list (nconc (nreverse (cdr reader::stack)) 
				     (car reader::stack))))
	   (t 
	    (reader::error "`)' doesn't end a list"))))))
	
(set-macro-character ?\.
  (function 
   (lambda (stream char)
     (and (eq reader::context 'dotted-pair) 
	  (reader::error "No more than one `.' allowed in list"))
     (throw 'dotted-pair nil))))

;; '(#\a . #\b)
;; '(a . (b . c))

;; Vectors: [a b]
(set-macro-character ?\[
  (function
   (lambda (stream char)
     (reader::read-sexp (1- (point))
       (let ((reader::context 'vector))
	 (catch 'read-vector
	   (let ((reader::context 'vector)
		 reader::stack)
	     (while t (push (reader::read-from-buffer stream 't)
			    reader::stack)))))))))

(set-macro-character ?\] 
  (function 
   (lambda (stream char)
     (if (eq reader::context 'vector)
	 (throw 'read-vector (apply 'vector (nreverse reader::stack)))
       (reader::error "`]' doesn't end a vector"))))) 

;; Quote and backquote/comma macro
(set-macro-character ?\'
  (function
   (lambda (stream char)
     (reader::read-sexp (1- (point))
       (list (reader::read-sexp (point) 'quote)
	     (reader::read-from-buffer stream 't))))))

(set-macro-character ?\`
  (function
   (lambda (stream char)
     (if (= (following-char) ?\ )
	 ;; old backquote syntax. This is ambigous, because 
	 ;; (`(sexp)) is a valid form in both syntaxes, but 
	 ;; unfortunately not the same. 
	 ;; old syntax: read -> (` (sexp))
	 ;; new syntax: read -> ((` (sexp)))
	 (reader::read-sexp (1- (point)) '\`)
       (reader::read-sexp (1- (point))
	 (list (reader::read-sexp (point) '\`)
	       (reader::read-from-buffer stream 't)))))))

(set-macro-character ?\,
  (function
   (lambda (stream char)
     (cond ((eq (following-char) ?\ )
	    ;; old syntax
	    (reader::read-sexp (point) '\,))
	   ((eq (following-char) ?\@)
	    (forward-char 1)
	    (cond ((eq (following-char) ?\ )
		   (reader::read-sexp (point) '\,\@))
		  (t
		   (reader::read-sexp (- (point) 2)
		     (list 
		      (reader::read-sexp (point) '\,\@)
		      (reader::read-from-buffer stream 't))))))
	   (t
	    (reader::read-sexp (1- (point))
	      (list
	       (reader::read-sexp (1- (point)) '\,)
	       (reader::read-from-buffer stream 't))))))))

;; 'a
;; '(a b c)
;; (let ((a 10) (b '(20 30))) `(,a ,@b c))
;; the old syntax is also supported:
;; (let ((a 10) (b '(20 30))) (` ((, a) (,@ b) c)))

;; Single line character comment:  ; 
(set-macro-character ?\;
  (function
   (lambda (stream char)
     (skip-chars-forward "^\n\r")
     (throw 'reader-ignore nil))))



;; Dispatch character character #
(make-dispatch-macro-character ?\#)

(defsubst reader::check-0-infix (n)
  (or (= n 0) 
      (reader::error "Numeric infix argument not allowed: %d" n)))


(defalias 'search-forward-regexp 're-search-forward)

;; nested multi-line comments #| ... |#
(set-dispatch-macro-character ?\# ?\|
  (function 
   (lambda (stream char n)
     (reader::check-0-infix n)
     (let ((counter 0))
       (while (search-forward-regexp "#|\\||#" nil t)
	 (if (string-equal
	      (buffer-substring
	       (match-beginning 0) (match-end 0))
	      "|#")
	     (cond ((> counter 0)
		    (decf counter))
		   ((= counter 0)
		    ;; stop here
		    (goto-char (match-end 0))
		    (throw 'reader-ignore nil))
		   ('t
		    (reader::error "Unmatching closing multicomment")))
	   (incf counter)))
       (reader::error "Unmatching opening multicomment")))))

;; From cl-packages.el
(defconst reader::symbol-characters "[A-Za-z0-9-_!@$%^&*+=|~{}<>/]")
(defconst reader::symbol-regexp2
  (format "\\(%s+\\)" reader::symbol-characters))

(set-dispatch-macro-character ?\# ?\:
  (function
   (lambda (stream char n)
     (reader::check-0-infix n)
     (or (looking-at reader::symbol-regexp2)
	 (reader::error "Invalid symbol read syntax"))
     (goto-char (match-end 0))
     (make-symbol 
      (buffer-substring (match-beginning 0) (match-end 0))))))

;; Function quoting: #'<function>
(set-dispatch-macro-character ?\# ?\'
  (function
   (lambda (stream char n)
     (reader::check-0-infix n)
     ;; Probably should test if cl is required by current buffer.
     ;; Currently, cl will always be a feature because cl-read requires it.
     (reader::read-sexp (- (point) 2)
       (list 
	(reader::read-sexp (point) (if (featurep 'cl)  'function* 'function))
	(reader::read-from-buffer stream 't))))))

;; Character syntax: #\<char> 
;; Not yet implemented: #\Control-a #\M-C-a etc. 
;; This definition is not used - the next one is more general.
'(set-dispatch-macro-character ?# ?\\
  (function 
   (lambda (stream char n)
     (reader::check-0-infix n)
     (let ((next (following-char))
           name)
       (if (not (and (<= ?a next) (<= next ?z)))
           (progn (forward-char 1) next)
         (setq next (reader::read-from-buffer stream t))
         (cond ((symbolp next) (setq name (symbol-name next)))
               ((integerp next) (setq name (int-to-string next))))
         (if (= 1 (length name))
             (string-to-char name)
           (case next
             (linefeed  ?\n)
             (newline   ?\r)
             (space     ?\ )
             (rubout    ?\b)
             (page      ?\f)
             (tab       ?\t)
             (return    ?\C-m)
             (t
              (reader::error "Unknown character specification `%s'"
			     next))))))))
  )

(defvar reader::special-character-name-table
  '(("linefeed"	. ?\n)
    ("newline"	. ?\r)
    ("space"	. ?\ )
    ("rubout"	. ?\b)
    ("page"	. ?\f)
    ("tab"        . ?\t)
    ("return"	. ?\C-m)))

(set-dispatch-macro-character ?# ?\\
  (function 
   (lambda (stream char n)
     (reader::check-0-infix n)
     (forward-char -1)
     ;; We should read in a special package to avoid creating symbols.
     (let ((symbol (reader::read-from-buffer stream t))
	   (case-fold-search t)
	   name modifier character char-base)
       (setq name (symbol-name symbol))
       (if (string-match "^\\(meta-\\|m-\\|control-\\|c-\\)+" name)
	   (setq modifier (substring name
				     (match-beginning 1)
				     (match-end 1))
		 character (substring name (match-end 1)))
	 (setq character name))
       (setq char-base 
	     (cond ((= (length character) 1)
		    (string-to-char character))
		   ('t 
		    (cdr (assoc character 
				reader::special-character-name-table)))))
       (or char-base 
	   (reader::error
	    "Unknown character specification `%s'" character))
	
       (and modifier
	    (progn 
	      (and (string-match "control-\\|c-" modifier)
		   (decf char-base 32))
	      (and (string-match "meta-\\|m-" modifier)
		   (incf char-base 128))))
       char-base))))

;; '(#\meta-space #\tab #\# #\> #\< #\a #\A  #\return #\space)
;; (eq #\m-tab ?\M-\t)
;; (eq #\c-m-x #\m-c-x)
;; (eq #\Meta-Control-return #\M-C-return)
;; (eq #\m-m-c-c-x #\m-c-x)
;; #\C-space #\C-@ ?\C-@



;; Read and load time evaluation:  #.<form>
;; Not yet implemented: #,<form>
(set-dispatch-macro-character ?\# ?\.
  (function 
   (lambda (reader::stream reader::char reader::n)
     (reader::check-0-infix reader::n)
     ;; This eval will see all internal vars of reader, 
     ;; e.g. stream, reader::recursive-p.  Anything that might be bound.
     ;; We must use `read' here rather than read-from-buffer with 'recursive-p
     ;; because the expression must not have unresolved #n#s in it anyway.
     ;; Otherwise the top-level expression must be completely read before
     ;; any embedded evaluation(s) occur(s).  CLtL2 does not specify this.
     ;; Also, call `read' so that it may be customized, by e.g. Edebug
     (eval (read reader::stream)))))
;; '(#.(current-buffer) #.(get-buffer "*scratch*"))

;; Path names (kind of):  #p<string>, #P<string>,
(set-dispatch-macro-character ?\# ?\P
  (function 
   (lambda (stream char n)
     (reader::check-0-infix n)
     (let ((string (reader::read-from-buffer stream 't)))
       (or (stringp string) 
	   (reader::error "Pathname must be a string: %s" string))
       (expand-file-name string)))))

(set-dispatch-macro-character ?\# ?\p
  (get-dispatch-macro-character ?\# ?\P))

;; #P"~/.emacs"
;; #p"~root/home" 

;; Feature reading:  #+<feature>,  #-<feature>
;; Not yet implemented: #+<boolean expression>, #-<boolean expression>


(defsubst reader::read-feature (stream char n flag)
  (reader::check-0-infix n)
  (let (;; Use the original reader to only read the feature.
	;; This is not exactly correct without *read-suppress*.
	;; Also Emacs 18 read goes one too far,
	;; so we assume there is a space after the feature.
	(feature (reader::original-read stream))
	(object (reader::read-from-buffer stream 't)))
    (if (eq (featurep feature) flag)
	object
      ;; Ignore it.
      (throw 'reader-ignore nil))))

(set-dispatch-macro-character ?\# ?\+
  (function 
   (lambda (stream char n)
     (reader::read-feature stream char n t))))

(set-dispatch-macro-character ?\# ?\-
  (function 
   (lambda (stream char n)
     (reader::read-feature stream char n nil))))

;; (#+cl loop #+cl do #-cl while #-cl t (body))




;; Shared structure reading: #<n>=, #<n>#

;; Reading of sexpression with shared and circular structure read
;; syntax  is done in two steps:
;; 
;; 1. Create an sexpr with unshared structures, just as the ordinary
;;    read macros do, with two exceptions: 
;;    - each label (#<n>=) creates, as a side effect, a symbolic
;;      reference for the sexpr that follows it
;;    - each reference (#<n>#) is replaced by the corresponding
;;      symbolic reference. 
;;
;; 2. This non-cyclic and unshared lisp structure is given to the
;;    function `reader::restore-shared-structure' (see
;;    `reader::read-from-buffer'), which simply replaces
;;    destructively all symbolic references by the lisp structures the
;;    references point at. 
;;
;; A symbolic reference is an uninterned symbol whose name is obtained
;; from the label/reference number using the function `int-to-string': 
;;
;; There are two non-locally used variables (bound in
;; `reader::read-from-buffer') which control shared structure reading: 
;; `reader::shared-structure-labels': 
;;	A list of integers that correspond to the label numbers <n> in
;;      the string currently read. This is used to avoid multiple
;;      definitions of the same label.
;; `reader::shared-structure-references': 
;;      The list of symbolic references that will be used as temporary
;;      placeholders for the shared objects introduced by a reference
;;      with the same number identification.

(set-dispatch-macro-character ?\# ?\=
  (function 
   (lambda (stream char n)
     (and (= n 0) (reader::error "0 not allowed as label"))
     ;; check for multiple definition of the same label
     (if (memq n reader::shared-structure-labels)
	 (reader::error "Label defined twice")
       (push n reader::shared-structure-labels))
     ;; create an uninterned symbol as symbolic reference for the label
     (let* ((string (int-to-string n))
	    (ref (or (find string reader::shared-structure-references
			   :test 'string=)
		     (first 
		      (push (make-symbol string) 
			    reader::shared-structure-references)))))
       ;; the link between the symbolic reference and the lisp
       ;; structure it points at is done using the symbol value cell
       ;; of the reference symbol.
       (setf (symbol-value ref) 
	     ;; this is also the return value 
	     (reader::read-from-buffer stream 't))))))


(set-dispatch-macro-character ?\# ?\#
  (function
   (lambda (stream char n)
     (and (= n 0) (reader::error "0 not allowed as label"))
     ;; use the non-local variable `reader::recursive-p' (from the reader
     ;; main loop) to detect labels at the top level of an sexpr.
     (if (not reader::recursive-p)
	 (reader::error "References at top level not allowed"))
     (let* ((string (int-to-string n))
	    (ref (or (find string reader::shared-structure-references
			   :test 'string=)
		     (first
		      (push (make-symbol string) 
			    reader::shared-structure-references)))))
       ;; the value of reading a #n# form is a reference symbol
       ;; whose symbol value is or will be the shared structure. 
       ;; `reader::restore-shared-structure' then replaces the symbol by
       ;; its value.
       ref))))

(defun reader::restore-shared-structure (obj)
  ;; traverses recursively OBJ and replaces all symbolic references by
  ;; the objects they point at. Remember that a symbolic reference is
  ;; an uninterned symbol whose value is the object it points at. 
  (cond 
   ((consp obj)
    (loop for rest on obj
	  as lastcdr = rest
	  do
	  (if;; substructure is a symbolic reference
	      (memq (car rest) reader::shared-structure-references)
	      ;; replace it by its symbol value, i.e. the associated object
	      (setf (car rest) (symbol-value (car rest)))
	    (reader::restore-shared-structure (car rest)))
	  finally 
	  (if (memq (cdr lastcdr) reader::shared-structure-references)
	      (setf (cdr lastcdr) (symbol-value (cdr lastcdr)))
	    (reader::restore-shared-structure (cdr lastcdr)))))
   ((vectorp obj)
    (loop for i below (length obj)
	  do
	  (if;; substructure  is a symbolic reference
	      (memq (aref obj i) reader::shared-structure-references)
	      ;; replace it by its symbol value, i.e. the associated object
	      (setf (aref obj i) (symbol-value (aref obj i)))
	    (reader::restore-shared-structure (aref obj i))))))
  obj)


;; #1=(a b #3=[#2=c])
;; (#1=[#\return #\a] #1# #1#)
;; (#1=[a b c] #1# #1#)
;; #1=(a b . #1#)

;; Creation and initialization of an internal standard readtable. 
;; Do this after all the macros and dispatch chars above have been defined.

(defconst reader::internal-standard-readtable (copy-readtable)
  "The original (CL-like) standard readtable. If you ever modify this
readtable, you won't be able to recover a standard readtable using
\(copy-readtable nil\)")


;; Replace built-in functions that call the built-in reader
;; 
;; The following functions are replaced here: 
;;
;; read			by	reader::read
;; read-from-string	by	reader::read-from-string
;;
;; eval-expression	by	reader::eval-expression
;; Why replace eval-expression? Not needed for Lucid Emacs since the
;; reader for arguments is also written in Lisp, and so may be overridden.
;;
;; eval-current-buffer  by	reader::eval-current-buffer
;; eval-buffer		by	reader::eval-buffer
;; original-eval-region by	reader::original-eval-region


;; Temporary read buffer used for reading from strings
(defconst reader::tmp-buffer
  (get-buffer-create " *CL Read*"))

;; Save a pointer to the original read function
(or (fboundp 'reader::original-read)
    (fset 'reader::original-read  (symbol-function 'read)))

(defun reader::read (&optional stream reader::recursive-p)
  "Read one Lisp expression as text from STREAM, return as Lisp object.
If STREAM is nil, use the value of `standard-input' \(which see\).
STREAM or the value of `standard-input' may be:
 a buffer \(read from point and advance it\)
 a marker \(read from where it points and advance it\)
 a string \(takes text from string, starting at the beginning\)
 t \(read text line using minibuffer and use it\).

This is the cl-read replacement of the standard elisp function
`read'. The only incompatibility is that functions as stream arguments
are not supported."
  (if (not cl-read-active)
      (reader::original-read stream)
    (if (null stream)			; read from standard-input
	(setq stream standard-input))

    (if (eq stream 't)			; read from minibuffer
	(setq stream (read-from-minibuffer "Common Lisp Expression: ")))

    (cond 

     ((bufferp stream)			; read from buffer
      (reader::read-from-buffer stream reader::recursive-p))

     ((markerp stream)			; read from marker
      (save-excursion 
	(set-buffer (marker-buffer stream))
	(goto-char (marker-position stream))
	(reader::read-from-buffer (current-buffer) reader::recursive-p)))

     ((stringp stream)			; read from string
      (save-excursion
	(set-buffer reader::tmp-buffer)
	(auto-save-mode -1)
	(erase-buffer)
	(insert stream)
	(goto-char (point-min))
	(reader::read-from-buffer reader::tmp-buffer reader::recursive-p)))
     (t 
      (reader::error "Not a valid stream: %s" stream)))))

;; read-from-string
;; save a pointer to the original `read-from-string' function
(or (fboundp 'reader::original-read-from-string)
    (fset 'reader::original-read-from-string
	  (symbol-function 'read-from-string)))

(defun reader::read-from-string (string &optional start end)
  "Read one Lisp expression which is represented as text by STRING.
Returns a cons: (OBJECT-READ . FINAL-STRING-INDEX).
START and END optionally delimit a substring of STRING from which to read;
they default to 0 and (length STRING) respectively.

This is the cl-read replacement of the standard elisp function
`read-from-string'.  It uses the reader macros in *readtable* if
`cl-read-active' is non-nil in the current buffer."

  ;; Does it really make sense to have read-from-string depend on
  ;; what the current buffer happens to be?   Yes, so code that
  ;; has nothing to do with cl-read uses original reader.
  (if (not cl-read-active)
      (reader::original-read-from-string string start end)
    (or start (setq start 0))
    (or end (setq end (length string)))
    (save-excursion
      (set-buffer reader::tmp-buffer)
      (auto-save-mode -1)
      (erase-buffer)
      (insert (substring string 0 end))
      (goto-char (1+ start))
      (cons 
       (reader::read-from-buffer reader::tmp-buffer nil)
       (1- (point))))))

;; (read-from-string "abc (car 'a) bc" 4)
;; (reader::read-from-string "abc (car 'a) bc" 4)
;; (read-from-string "abc (car 'a) bc" 2 11)
;; (reader::read-from-string "abc (car 'a) bc" 2 11)
;; (reader::read-from-string "`(car ,first ,@rest)")
;; (read-from-string ";`(car ,first ,@rest)")
;; (reader::read-from-string ";`(car ,first ,@rest)")

;; We should replace eval-expression, too, so that it reads (and
;; evals) in the current buffer.  Alternatively, this could be fixed
;; in C.  In Lemacs 19.6 and later, this function is already written
;; in lisp, and based on more primitive read functions we already
;; replaced. The reading happens during the interactive parameter
;; retrieval, which is written in lisp, too.  So this replacement of
;; eval-expresssion is only required fro (FSF) Emacs 18 (and 19?).

(or (fboundp 'reader::original-eval-expression)
    (fset 'reader::original-eval-expression 
          (symbol-function 'eval-expression)))

(defun reader::eval-expression (reader::expression)
  "Evaluate EXPRESSION and print value in minibuffer.
Value is also consed on to front of variable `values'."
  (interactive 
   (list
    (car (read-from-string
          (read-from-minibuffer 
           "Eval: " nil 
           ;;read-expression-map ;; not for emacs 18
           nil ;; use default map
           nil ;; don't do read with minibuffer current.
           ;; 'edebug-expression-history ;; not for emacs 18
           )))))
  (setq values (cons (eval reader::expression) values))
  (prin1 (car values) t))

(require 'eval-reg "eval-reg")
(require 'advice)


;; installing/uninstalling the cl reader
;; These two should always be used in pairs, or just install once and
;; never uninstall. 
(defun cl-reader-install ()
  (interactive)
  (fset 'read 			'reader::read)
  (fset 'read-from-string 	'reader::read-from-string)
  (fset 'eval-expression 	'reader::eval-expression)
  (elisp-eval-region-install))

(defun cl-reader-uninstall ()
  (interactive)
  (fset 'read 		       
	(symbol-function 'reader::original-read))
  (fset 'read-from-string	
	(symbol-function 'reader::original-read-from-string))
  (fset 'eval-expression
	(symbol-function 'reader::original-eval-expression))
  (elisp-eval-region-uninstall))

;; Globally installing the cl-read replacement functions is safe, even
;; for buffers without cl read syntax. The buffer local variable
;; `cl-read-active' controls whether the replacement funtions of this
;; package or the original ones are actually called.
(cl-reader-install)
(cl-reader-uninstall)

;; Advise the redefined eval-region
(defadvice eval-region (around cl-read activate)
  "Use the reader::read instead of the original read if cl-read-active."
  (with-elisp-eval-region (not cl-read-active)
    (ad-do-it)))
;;(ad-unadvise 'eval-region)


(add-hook 'emacs-lisp-mode-hook 'cl-reader-autoinstall-function)

'(defvar read-syntax)

'(defun cl-reader-autoinstall-function () 
  "Activates the Common Lisp style reader for emacs-lisp-mode buffers,
if the property line has a local variable setting like this: 
\;\; -*- Read-Syntax: Common-Lisp -*-"
  ;; this is a hack to avoid recursion in the case that the prop line 
  ;; containes "Mode: emacs-lisp" entry
  (or (boundp 'local-variable-hack-done)
      (let (local-variable-hack-done
	    (case-fold-search t))
	;; Usually `hack-local-variables-prop-line' is called only after
	;; installation of the major mode. But we need to know about the
	;; local variables before that, so we call the local variable hack
	;; explicitly here:
	(hack-local-variables-prop-line 't)
	;; But hack-local-variables-prop-line not defined in emacs 18.
	(cond 
	 ((and (boundp 'read-syntax)
	       read-syntax
	       (string-match "^common-lisp$" (symbol-name read-syntax)))
	  (require 'cl-read)
	  (make-local-variable 'cl-read-active)
	  (setq cl-read-active 't))))))

;; Emacs 18 doesnt have hack-local-variables-prop-line.  So use this instead.
(defun cl-reader-autoinstall-function ()
  (save-excursion
    (goto-char (point-min))
    (let ((case-fold-search t))
      (cond ((re-search-forward 
	      "read-syntax: *common-lisp" 
	      (save-excursion 
		(end-of-line)
		(point))
	      t)
	     (require 'cl-read)
	     (make-local-variable 'cl-read-active)
	     (setq cl-read-active t))))))


(run-hooks 'cl-read-load-hooks)
;; end cl-read.el
