A reader macro in a macro

Discussion of Common Lisp
Post Reply
Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

A reader macro in a macro

Post by Goheeca » Fri Nov 02, 2012 10:39 am

I've wanted to create macro in this way:

Code: Select all

(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars collect `(,(first var) (#_new ,@(rest var))))
     ,@body))
Where #_ is the commonqt reader macro. Of course, it doesn't work.
So I've created cl-rttemplate which works in a similar way as quasiquoting, but in the read-time. Then the macro looks like this (for details go to the homepage of project):

Code: Select all

(setf (readtable-case cl-rttemplate:*rt*) :preserve)
(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars collect `(,(first var) #"(#_new " #@',(rest var) ")"#))
     ,@body))
So what do you think about it? Or would you have a better solution?
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: A reader macro in a macro

Post by wvxvw » Fri Nov 02, 2012 1:49 pm

What would the macro normally expand to? Won't it be possible to replace it with a funcall or something like that?

Also, I've tried it with some other custom-tailored reader-macro, and it expanded as expected:

Code: Select all

(set-macro-character
 #\[
 #'(lambda (stream char)
     (declare (ignore char))
     (set-syntax-from-char #\] #\;)
     (let ((forms (read-delimited-list #\] stream t)))
       (set-syntax-from-char #\] #\x)
       (append '(funcall) forms))))

(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars collect `(,(first var) [,@(rest var)]))
     ,@body))

(nlet ((a 100) (b 200)) (format t "a: ~s, b: ~s~&" a b))

;; (LET ((A (FUNCALL 100)) (B (FUNCALL 200)))
;;   (FORMAT T "a: ~s, b: ~s~&" A B))
Maybe it is not interpreted correctly because of the preceding parenthesis? Can you show how it expands? Installing the entire Qt is a bit too much for me to test this :)

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: A reader macro in a macro

Post by Goheeca » Fri Nov 02, 2012 2:11 pm

Code: Select all

'(#_new QLabel "blah")
expands to:

Code: Select all

(QT-INTERNAL::|QLabel1| "blah")
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: A reader macro in a macro

Post by wvxvw » Fri Nov 02, 2012 4:19 pm

This is weird, because if I make something that mimics what that reader macro could probably do:

Code: Select all

;; :|wahever|
(set-dispatch-macro-character
 #\# #\_
 #'(lambda(s c n)
     (declare (ignore c n))
     (intern
      (with-output-to-string
        (result)
        (loop for c = (read-char s nil :eof)
              ;; This is for illustration only
              do (if (or (eq c :eof)
                         (char= c #\Space)
                         (char= c #\Tab)
                         (char= c #\Return)
                         (char= c #\Rubout)
                         (char= c #\Linefeed)
                         (char= c #\;)
                         (char= c #\)))
                     (return)
                   (write-char c result))))
      "KEYWORD")))

(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars collect `(,(first var) (#_foo ,@(rest var))))
     ,@body))

(nlet ((a 100) (b 200)) (format t "a: ~s, b: ~s~&" a b))
;; (LET ((A (:|foo| 100)) (B (:|foo| 200)))
;;   (FORMAT T "a: ~s, b: ~s~&" A B))
Then, I think, it works as you'd expect it, does it?

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: A reader macro in a macro

Post by Paul » Fri Nov 02, 2012 10:43 pm

The problem is, the OP wanted to write (#_new ,@(rest var)) and #_ apparently wants to read two more symbols from the input stream to find out what to expand into (i.e., NEW and QLABEL) — so ,@(rest var) needs to be expanded before the reader macro takes hold.

Which tells you you're doing something wrong (or someone else is...).

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: A reader macro in a macro

Post by wvxvw » Sat Nov 03, 2012 2:50 am

Oh! I see now, well, here's something I could think of, in case it helps:

Code: Select all

(set-dispatch-macro-character
 #\# #\_
 #'(lambda(s c n)
     (declare (ignore c n))
     (intern
      (with-output-to-string
        (result)
        (loop for c = (read-char s nil :eof)
              with symbols-read = 0
              ;; This is for illustration only
              do (if (or (eq c :eof)
                         (char= c #\Space)
                         (char= c #\Tab)
                         (char= c #\Return)
                         (char= c #\Rubout)
                         (char= c #\Linefeed)
                         (char= c #\;)
                         (char= c #\)))
                     (if (= symbols-read 0)
                         (incf symbols-read)
                       (return))
                   (write-char c result))))
      "KEYWORD")))

(defun nlet-helper (var-first var-second var-rest)
  (list var-first
        (append
         (list (read-from-string
                (format nil "#_new ~a" var-second)))
         var-rest)))

(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars
               collect (nlet-helper (first var) (second var) (cddr var)))
     ,@body))

(nlet ((a 100 x) (b 200 y)) (format t "a: ~s, b: ~s~&" a b))
;; (LET ((A (:|new100| X)) (B (:|new200| Y)))
;;   (FORMAT T "a: ~s, b: ~s~&" A B))

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: A reader macro in a macro

Post by Goheeca » Sat Nov 03, 2012 3:05 am

Yeah, the #_ reads a list delimited by a parenthesis and I want to use this reader macro in a concisely form in my macro.
Here is an exhibition:

Code: Select all

(qt:enable-syntax)
(rtt:enable-syntax)
(setf (readtable-case rtt:*rt*) :preserve)

(defmacro gui ((&rest args) &body body)
  `(let ((app (qt:make-qapplication ,@args)))
     (unwind-protect
          (progn ,@body
             (#_exec app))
       (#_delete app))))

(defmacro nlet ((&rest vars) &body body)
  `(let ,(loop for var in vars collect `(,(first var) #"(#_new " #@',(rest var) ")"#))
     ,@body))
then:

Code: Select all

(gui ("arg0" "arg1")
  (nlet ((label |QLabel| "A sample string"))
    (#_resize label 200 200)
    (#_show label)))
Just to hide #_new and not to repeat oneself, although it doesn't make very sense in this example, but I came across this issue and I felt restricted.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: A reader macro in a macro

Post by Goheeca » Sat Nov 03, 2012 3:17 am

Some more expansions:

Code: Select all

* '(#_new QLabel "foo")

(QT-INTERNAL::|QLabel1| "foo")
* '(#_new QLabel "bar")

(QT-INTERNAL::|QLabel1| "bar")
* '(#_new QWidget "baz")

(QT-INTERNAL::|QWidget2| "baz")
* '(#_resize label 100 100)

(QT-INTERNAL::|resize3| LABEL 100 100)
* '(#_exec app)

(QT-INTERNAL::|exec4| APP)
* '(#_delete app)

(QT:OPTIMIZED-DELETE APP)
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: A reader macro in a macro

Post by Goheeca » Sat Nov 03, 2012 8:51 am

According to the source code #_ doesn't read a list delimited by a parenthesis, but in a general way it reads a various count of arguments and principally it's a internal business of commonqt.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: A reader macro in a macro

Post by Goheeca » Sat Nov 03, 2012 12:17 pm

I've improved nlet if someone would like to use it.
Firstly I present an intermediate step:

Code: Select all

(defmacro nlet ((&rest vars) &body body)
  `(let* ,(loop for var in vars collect `(,(first var) #"(#_new " #@`(,',(second var) ,,@(cddr var)) ")"#))
     ,@body))
And the final version:

Code: Select all

(defmacro nlet ((&rest vars) &body body)
  `(let* ,(loop for var in vars collect `(,(first var) (,#"'#_new " (second var) ""# ,@(cddr var))))
     ,@body)
The intermediate step doesn't work with unreadable objects, but it should be always avoidable (like in the final version), because other reader macros can't read them either.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Post Reply