Page 1 of 1
A reader macro in a macro
Posted: Fri Nov 02, 2012 10:39 am
by Goheeca
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?
Re: A reader macro in a macro
Posted: Fri Nov 02, 2012 1:49 pm
by wvxvw
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
Re: A reader macro in a macro
Posted: Fri Nov 02, 2012 2:11 pm
by Goheeca
Re: A reader macro in a macro
Posted: Fri Nov 02, 2012 4:19 pm
by wvxvw
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?
Re: A reader macro in a macro
Posted: Fri Nov 02, 2012 10:43 pm
by Paul
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...).
Re: A reader macro in a macro
Posted: Sat Nov 03, 2012 2:50 am
by wvxvw
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))
Re: A reader macro in a macro
Posted: Sat Nov 03, 2012 3:05 am
by Goheeca
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.
Re: A reader macro in a macro
Posted: Sat Nov 03, 2012 3:17 am
by Goheeca
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)
Re: A reader macro in a macro
Posted: Sat Nov 03, 2012 8:51 am
by Goheeca
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.
Re: A reader macro in a macro
Posted: Sat Nov 03, 2012 12:17 pm
by Goheeca
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.