From: Vladimir Zolotykh
Subject: Changing reader syntax locally
Date: 
Message-ID: <20060322151831.02e8b90c.gsmith@eurocom.od.ua>
Suppose I have to functions

(defun %enable-tr2-syntax ()
  (unless *original-reader*
    (setq *original-reader* (get-macro-character *tr2-macro-char*)))
  (set-macro-character *tr2-macro-char* #'tr2-reader))

(defun %disable-tr2-syntax ()
  (when *original-reader*
    (set-macro-character *tr2-macro-char* *original-reader*))
  (setq *original-reader* nil))

They both work fine as far as I call them in REPL. However, to be
able to compile (using Allegro Emacs Lisp Interface) something like 

  (defun foo () [00:00:03])

I have to compile

  (eval-when (:compile-toplevel :load-toplevel :execute)
    (%enable-tr2-syntax))

first. Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
please tell me why? Are there two different reader tables for the REPL
and for compiler?

After that I thought it would be nice also to have some macro which
would enable this special syntax only for some fragment of
code. However my clumsy attempt like


  (with-tr2-syntax [00:00:01])

was destined to fail. Is there any way to achive that, e.g. to have
some piece of code both compiled and executed with special syntax
enabled?

-- 
Vladimir Zolotykh

From: Kaz Kylheku
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <1143057660.513971.298870@i39g2000cwa.googlegroups.com>
Vladimir Zolotykh wrote:
>I have to compile
>
>
> (eval-when (:compile-toplevel :load-toplevel :execute)
>  (%enable-tr2-syntax))

The :EXECUTE is useless here, because the read table matters is when
the raw source code is being scanned.  The times when that happens are
when the .lisp file is loaded (as opposed to the .fasl) or when the
.lisp is being compiled to .fasl.

> Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
> please tell me why? Are there two different reader tables for the REPL
> and for compiler?

No, LOAD and COMPILE file do not reset the *PACKAGE* or *READTABLE*
variables. rather, they create new dynamic bindings for them, but with
the existing values. This means that the file inherits the package and
readable environment from the caller, but the caller is protected from
assignments to these variables.

Could it be that you are somehow loading a compiled version of the file
instead of the source?

> After that I thought it would be nice also to have some macro which
> would enable this special syntax only for some fragment of
> code. However my clumsy attempt like
>
>
>   (with-tr2-syntax [00:00:01])
>
> was destined to fail.

Yes. The whole form has to be read before the macro is expanded, so
it's too late to influence the syntax then. You need the read syntax to
be in place in order to read the form which contains it.

Nevertheless, you could implement a hack which would allow the above to
work. Basically, you'd have to hook into the ( reader macro. You'd read
the next token, and then if it's the WITH-TR2-SYNTAX symbol, you'd
switch to your custom readtable before reading the rest of the list to
the closing parenthesis.

There would still be a WITH-TR2-SYNTAX macro, but it would just expand
to PROGN.

Sometimes a macro is not really a macro. For instance in LaTeX, when
you end a verbatim section of text started by \begin{verbatim} with
\end{verbatim}, that \end{verbatim} is not TeX macro call at all. The
characters "\end{verbatim}" are literally recognized by the verbatim
text scanner. That falls into the same category of hack.
From: Peter Seibel
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <m2zmji1r3r.fsf@gigamonkeys.com>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> Suppose I have to functions
>
> (defun %enable-tr2-syntax ()
>   (unless *original-reader*
>     (setq *original-reader* (get-macro-character *tr2-macro-char*)))
>   (set-macro-character *tr2-macro-char* #'tr2-reader))
>
> (defun %disable-tr2-syntax ()
>   (when *original-reader*
>     (set-macro-character *tr2-macro-char* *original-reader*))
>   (setq *original-reader* nil))
>
> They both work fine as far as I call them in REPL. However, to be
> able to compile (using Allegro Emacs Lisp Interface) something like 
>
>   (defun foo () [00:00:03])
>
> I have to compile
>
>   (eval-when (:compile-toplevel :load-toplevel :execute)
>     (%enable-tr2-syntax))
>
> first. Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
> please tell me why? Are there two different reader tables for the REPL
> and for compiler?

It's possible that there are if the compilation is happening in a
different thread. I.e. if *READTABLE* is bound in the REPL thread,
you're changes to it won't affect the top-level *READTABLE* that
COMPILE-FILE will use. But that's just a guess. You might want to try
the same thing from an alisp run at the command line to check this
theory. Run your %enable-tr2-syntax and then (compile-file ...).

> After that I thought it would be nice also to have some macro which
> would enable this special syntax only for some fragment of code.
> However my clumsy attempt like
>
>
>   (with-tr2-syntax [00:00:01])
>
> was destined to fail. Is there any way to achive that, e.g. to have
> some piece of code both compiled and executed with special syntax
> enabled?

You'd have to write it as a reader macro too. Maybe something like this:

  {tr2-syntax
    (lisp stuff here [00:00:001])}

where the reader macro for #\{ expects to read a symbol which it will
interpet as the name of some syntax to enable and then some number of
Lisp forms that it will READ after binding *READTABLE*
appropriately.

-Peter  

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Raffael Cavallaro
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <2006032215055550073-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2006-03-22 09:39:04 -0500, Peter Seibel <·····@gigamonkeys.com> said:

> You'd have to write it as a reader macro too. Maybe something like this:
> 
>   {tr2-syntax
>     (lisp stuff here [00:00:001])}
> 
> where the reader macro for #\{ expects to read a symbol which it will
> interpet as the name of some syntax to enable and then some number of
> Lisp forms that it will READ after binding *READTABLE*
> appropriately.

Tim Bradshaw has this available in his read-time packages:
<http://www.tfeb.org/lisp/hax.html#READ-PACKAGES>
From: Raffael Cavallaro
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <2006032215080343658-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2006-03-22 15:05:55 -0500, Raffael Cavallaro 
<················@pas-d'espam-s'il-vous-plait-mac.com> said:

> Tim Bradshaw has this available in his read-time packages:
> <http://www.tfeb.org/lisp/hax

Sorry, should say, Tim Bradshaw has the mechanics for doing this in his 
read-time packages - just rewrite it to rebind *readtable* rather than 
*package*.
From: Pascal Bourguignon
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <87d5gez41q.fsf@thalassa.informatimago.com>
Peter Seibel <·····@gigamonkeys.com> writes:
>> first. Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
>> please tell me why? Are there two different reader tables for the REPL
>> and for compiler?
>
> It's possible that there are if the compilation is happening in a
> different thread. I.e. if *READTABLE* is bound in the REPL thread,
> you're changes to it won't affect the top-level *READTABLE* that
> COMPILE-FILE will use. But that's just a guess. You might want to try
> the same thing from an alisp run at the command line to check this
> theory. Run your %enable-tr2-syntax and then (compile-file ...).
>
>> After that I thought it would be nice also to have some macro which
>> would enable this special syntax only for some fragment of code.
>> However my clumsy attempt like
>>
>>
>>   (with-tr2-syntax [00:00:01])
>>
>> was destined to fail. Is there any way to achive that, e.g. to have
>> some piece of code both compiled and executed with special syntax
>> enabled?
>
> You'd have to write it as a reader macro too. Maybe something like this:
>
>   {tr2-syntax
>     (lisp stuff here [00:00:001])}
>
> where the reader macro for #\{ expects to read a symbol which it will
> interpet as the name of some syntax to enable and then some number of
> Lisp forms that it will READ after binding *READTABLE*
> appropriately.

Or you can merely do:

(eval-when (:compile-toplevel :load-toplevel :execute) (%enable-tr2-syntax))
(lisp stuff here [00:00:001])
(eval-when (:compile-toplevel :load-toplevel :execute) (%disable-tr2-syntax))


This:

  (with-tr2-syntax [00:00:01])

doesn't work because the whole form is READ before being EVALuated!

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"This machine is a piece of GAGH!  I need dual Opteron 850
processors if I am to do battle with this code!"
From: Vladimir Zolotykh
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <20060325111636.72165068.gsmith@eurocom.od.ua>
On Wed, 22 Mar 2006 14:39:04 GMT
Peter Seibel <·····@gigamonkeys.com> wrote:

> Vladimir Zolotykh <······@eurocom.od.ua> writes:
> 
> > Suppose I have to functions
> >
> > (defun %enable-tr2-syntax ()
> >   (unless *original-reader*
> >     (setq *original-reader* (get-macro-character *tr2-macro-char*)))
> >   (set-macro-character *tr2-macro-char* #'tr2-reader))
> >
> > (defun %disable-tr2-syntax ()
> >   (when *original-reader*
> >     (set-macro-character *tr2-macro-char* *original-reader*))
> >   (setq *original-reader* nil))
> >
> > They both work fine as far as I call them in REPL. However, to be
> > able to compile (using Allegro Emacs Lisp Interface) something like 
> >
> >   (defun foo () [00:00:03])
> >
> > I have to compile
> >
> >   (eval-when (:compile-toplevel :load-toplevel :execute)
> >     (%enable-tr2-syntax))
> >
> > first. Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
> > please tell me why? Are there two different reader tables for the REPL
> > and for compiler?
> 
> It's possible that there are if the compilation is happening in a
> different thread. I.e. if *READTABLE* is bound in the REPL thread,
> you're changes to it won't affect the top-level *READTABLE* that
> COMPILE-FILE will use. But that's just a guess. You might want to try
> the same thing from an alisp run at the command line to check this
> theory. Run your %enable-tr2-syntax and then (compile-file ...).

They're different after all!
The following trick makes them the same.

  ;; -*- mode: common-lisp; package: cl-user; readtable: mytable -*-
  (in-package :cl-user)

  (eval-when (:compile-toplevel :load-toplevel :execute)
    (setq *readtable* (named-readtable :mytable)))

Before I could compile or evaluate forms in that file I must do

  (setf (named-readtable :mytable) *readtable*

in the *common-lisp* buffer.

If you know a more convenient way I'd appreciate if you let me know.

> 
> > After that I thought it would be nice also to have some macro which
> > would enable this special syntax only for some fragment of code.
> > However my clumsy attempt like
> >
> >
> >   (with-tr2-syntax [00:00:01])
> >
> > was destined to fail. Is there any way to achive that, e.g. to have
> > some piece of code both compiled and executed with special syntax
> > enabled?
> 
> You'd have to write it as a reader macro too. Maybe something like this:
> 
>   {tr2-syntax
>     (lisp stuff here [00:00:001])}
> 
> where the reader macro for #\{ expects to read a symbol which it will
> interpet as the name of some syntax to enable and then some number of
> Lisp forms that it will READ after binding *READTABLE*
> appropriately.

Could you please take a glance at my attempt to do so?

  (defun |{-reader| (stream char)
    (declare (ignore char))
    (let ((*readtable* (copy-readtable))
	  (w (read stream t nil t)))
      (when (eq w 'tr2-syntax)
	(set-macro-character #\[ #'|[-reader|))
      (cons 'progn (read-delimited-list #\} stream t))))

  (set-macro-character #\{ '|{-reader|)
  (set-macro-character #\} (get-macro-character #\) nil))

The |[-reader| function is included after the signature. I don't think
it matters much, included it just in case.

What I specially don't like in the |{-reader| is the usage of READ to
get the word after opening {. It seems to me just not right. However I
couldn't think of anything better.


> 
> -Peter  
> 
> -- 
> Peter Seibel           * ·····@gigamonkeys.com
> Gigamonkeys Consulting * http://www.gigamonkeys.com/
> Practical Common Lisp  * http://www.gigamonkeys.com/book/


-- 
Vladimir Zolotykh

(defun |[-reader| (stream char)
  (declare (ignore char))
  (let (h m (s 0) c
	(str (make-array 0 :element-type 'character
			 :adjustable t :fill-pointer 0)))
    (labels ((next () 
	       (vector-push-extend 
		(setq c (read-char stream t (values) t)) str)
	       c)
	     (bad-format () (error "Bad time format in ~A" str))
	     (number ()
	       (let ((n 0))
		 (unless (digit-char-p c) (bad-format))
		 (setq n (digit-char-p c))
		 (when (digit-char-p (next))
		   (setq n (+ (* n 10) (digit-char-p c)))
		   (next))
		 n)))
      (next)
      (setq h (number))
      (unless (char= c #\:) (bad-format))
      (next)
      (setq m (number))
      (when (char= c #\:) 
	(next) 
	(setq s (number)))
      (unless (char= c #\]) (bad-format))
      (if (or (and (= h 24) (= m 0) (= s 0))
	      (and (<= 0 h 23) (<= 0 m 59) (<= 0 s 59)))
	  (+ s (* 60 (+ m (* 60 h))))
	(bad-format)))))
From: Marco Baringer
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <m2odzuohlj.fsf@bese.it>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> Could you please take a glance at my attempt to do so?
>
>   (defun |{-reader| (stream char)
>     (declare (ignore char))
>     (let ((*readtable* (copy-readtable))
> 	  (w (read stream t nil t)))
>       (when (eq w 'tr2-syntax)
> 	(set-macro-character #\[ #'|[-reader|))
>       (cons 'progn (read-delimited-list #\} stream t))))
>
>   (set-macro-character #\{ '|{-reader|)
>   (set-macro-character #\} (get-macro-character #\) nil))

i _just_ wrote something exaclty like this :). the only thing i'd
change is to not hard code the available syntaxes into the {
reader. note that (copy-readtable) will always return the standard
readtable, even if another readtable was in effect, you prbably want
(copy-readtable *readtable* nil).

anyway, here's what i came up with:

(defun |{-reader| (stream char)
  (declare (ignore char))
  "A utility read macro for modifying the read table.

The syntax is:

  {SPECIFIER ...}

SPECIFIER is either a symbol naming a function (available at read
time) or a list (SPECIFIER &rest ARGUMENTS). SPECIFIER is applied to
ARGUMENTS to produce the reader function function. The read function
is then called and passed another function which reads until the #\}
character. During the executen of the function *readtable* is bound to
a copy of the current read table.

See WITH-PACKAGE for an example of a specifier function."
  (let ((*readtable* (copy-readtable *readtable* nil)))
    (destructuring-bind (specifier &rest arguments)
        (ensure-list (read stream t nil t))
      (funcall (apply specifier arguments)
               (lambda ()
                 (read-delimited-list #\} stream t))))))

(defun enable-bracket-reader (&optional (readtable *readtable*))
  (set-macro-character #\{ #'|{-reader| t readtable)
  (set-syntax-from-char #\} #\) readtable nil))

(defun with-package (package-name)
  "When used as a specifier for the #\{ reader locally rebinds,
at read time, the current package to PACKAGE-NAME.

For example, this:

  {(with-package :cl) t}

Will always read cl:t, no matter what the current package
actually is."
  (lambda (reader)
    (let ((*package* (find-package package-name)))
      `(progn ,@(funcall reader)))))

> What I specially don't like in the |{-reader| is the usage of READ to
> get the word after opening {. It seems to me just not right. However I
> couldn't think of anything better.

i think it's perfectly fine, other wise you'll end up implemneting
your own special reader with, imho, no real gain.

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen
From: Vladimir Zolotykh
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <20060327131650.6430cfdb.gsmith@eurocom.od.ua>
On Sat, 25 Mar 2006 13:04:56 +0100
Marco Baringer <··@bese.it> wrote:

> i _just_ wrote something exaclty like this :).

Beautiful, beautiful!

I must say that there is a world of difference between your solution
and my attempt to solve in which attempt there is nothing but an idea
which is actually Peter's.

-- 
Vladimir Zolotykh
From: Peter Seibel
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <m2veu21wh3.fsf@gigamonkeys.com>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> On Wed, 22 Mar 2006 14:39:04 GMT
> Peter Seibel <·····@gigamonkeys.com> wrote:
>
>> Vladimir Zolotykh <······@eurocom.od.ua> writes:
>> 
>> > Suppose I have to functions
>> >
>> > (defun %enable-tr2-syntax ()
>> >   (unless *original-reader*
>> >     (setq *original-reader* (get-macro-character *tr2-macro-char*)))
>> >   (set-macro-character *tr2-macro-char* #'tr2-reader))
>> >
>> > (defun %disable-tr2-syntax ()
>> >   (when *original-reader*
>> >     (set-macro-character *tr2-macro-char* *original-reader*))
>> >   (setq *original-reader* nil))
>> >
>> > They both work fine as far as I call them in REPL. However, to be
>> > able to compile (using Allegro Emacs Lisp Interface) something like 
>> >
>> >   (defun foo () [00:00:03])
>> >
>> > I have to compile
>> >
>> >   (eval-when (:compile-toplevel :load-toplevel :execute)
>> >     (%enable-tr2-syntax))
>> >
>> > first. Typing (%enable-tr2-syntax) in REPL doesn't help. Would you
>> > please tell me why? Are there two different reader tables for the REPL
>> > and for compiler?
>> 
>> It's possible that there are if the compilation is happening in a
>> different thread. I.e. if *READTABLE* is bound in the REPL thread,
>> you're changes to it won't affect the top-level *READTABLE* that
>> COMPILE-FILE will use. But that's just a guess. You might want to try
>> the same thing from an alisp run at the command line to check this
>> theory. Run your %enable-tr2-syntax and then (compile-file ...).
>
> They're different after all!
> The following trick makes them the same.
>
>   ;; -*- mode: common-lisp; package: cl-user; readtable: mytable -*-
>   (in-package :cl-user)
>
>   (eval-when (:compile-toplevel :load-toplevel :execute)
>     (setq *readtable* (named-readtable :mytable)))
>
> Before I could compile or evaluate forms in that file I must do
>
>   (setf (named-readtable :mytable) *readtable*
>
> in the *common-lisp* buffer.
>
> If you know a more convenient way I'd appreciate if you let me know.
>
>> 
>> > After that I thought it would be nice also to have some macro which
>> > would enable this special syntax only for some fragment of code.
>> > However my clumsy attempt like
>> >
>> >
>> >   (with-tr2-syntax [00:00:01])
>> >
>> > was destined to fail. Is there any way to achive that, e.g. to have
>> > some piece of code both compiled and executed with special syntax
>> > enabled?
>> 
>> You'd have to write it as a reader macro too. Maybe something like this:
>> 
>>   {tr2-syntax
>>     (lisp stuff here [00:00:001])}
>> 
>> where the reader macro for #\{ expects to read a symbol which it will
>> interpet as the name of some syntax to enable and then some number of
>> Lisp forms that it will READ after binding *READTABLE*
>> appropriately.
>
> Could you please take a glance at my attempt to do so?
>
>   (defun |{-reader| (stream char)
>     (declare (ignore char))
>     (let ((*readtable* (copy-readtable))
> 	  (w (read stream t nil t)))
>       (when (eq w 'tr2-syntax)
> 	(set-macro-character #\[ #'|[-reader|))
>       (cons 'progn (read-delimited-list #\} stream t))))
>
>   (set-macro-character #\{ '|{-reader|)
>   (set-macro-character #\} (get-macro-character #\) nil))
>
> The |[-reader| function is included after the signature. I don't think
> it matters much, included it just in case.
>
> What I specially don't like in the |{-reader| is the usage of READ to
> get the word after opening {. It seems to me just not right. However I
> couldn't think of anything better.

I think that's in fact The Right Thing. You could check that the
object so read is in fact a symbol, or whatever you want to accept in
that first position, and issue a meaningful error if it's not. Other
than that, this looks fine modulo the few suggestions for improvements
Marco made.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Wade Humeniuk
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <6wcVf.5556$K11.2080@clgrps12>
Vladimir Zolotykh wrote:

> 
> Could you please take a glance at my attempt to do so?
> 
>   (defun |{-reader| (stream char)
>     (declare (ignore char))
>     (let ((*readtable* (copy-readtable))
> 	  (w (read stream t nil t)))
>       (when (eq w 'tr2-syntax)
> 	(set-macro-character #\[ #'|[-reader|))
>       (cons 'progn (read-delimited-list #\} stream t))))
> 
>   (set-macro-character #\{ '|{-reader|)
>   (set-macro-character #\} (get-macro-character #\) nil))
> 
> The |[-reader| function is included after the signature. I don't think
> it matters much, included it just in case.
> 
> What I specially don't like in the |{-reader| is the usage of READ to
> get the word after opening {. It seems to me just not right. However I
> couldn't think of anything better.
> 

In the interest of efficiency I would change the code to do,

(defun |{-reader| (stream char)
   (declare (ignore char))
   (let ((*readtable* (case (read stream t nil t)
                        (tr2-syntax (load-time-value
                                     (let ((copy (copy-readtable)))
                                       (set-macro-character #\[ #'|[-reader| nil copy)
                                       copy)))
                        (otherwise *readtable*))))
     (cons 'progn (read-delimited-list #\} stream t))))

This way you do not have to copy the readtable every time you call the
function.

Wade
From: Joerg Hoehle
Subject: Re: Changing reader syntax locally
Date: 
Message-ID: <uodzs9j3s.fsf@users.sourceforge.net>
Vladimir Zolotykh <······@eurocom.od.ua> writes:
> (defun %enable-tr2-syntax ()
>   (unless *original-reader*
>     (setq *original-reader* (get-macro-character *tr2-macro-char*)))
>   (set-macro-character *tr2-macro-char* #'tr2-reader))
> 
> (defun %disable-tr2-syntax ()
>   (when *original-reader*
>     (set-macro-character *tr2-macro-char* *original-reader*))
>   (setq *original-reader* nil))

>   (defun foo () [00:00:03])

This has nothing to do with your question, but note that the above
functions are not entirely correct.  First, GET-MACRO-CHARACTER
returns two values, but your code only saves and restores the primary
value.  The non-terminating property is eventually lost.

Second, in case GET-MACRO-CHARACTER returns NIL, your code fails to
reestablish the previous behaviour, and your handler remains active.

Alas, I don't know how to say "restore the implementation's default
behaviour", as NIL is not allowed for 'new-function'. Some
implementations will raise an error for NIL in SET-MACRO-CHARACTER.
All I could portably do is provide a handler that raises an error.

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center