Re: Help needed with macros: Brain turning to jelly
- From: Pascal Bourguignon <usenet@xxxxxxxxxxxxxxxxx>
- Date: Sat, 11 Feb 2006 01:09:05 +0100
Jeremy Smith <jeremynospam@xxxxxxxxxxxxxx> writes:
[...]
The macro has this input: '(('string buf) ('string val))
Most probably NOT.
QUOTE is used to avoid evaluation of the following form (to take it as
data), and is needed when we want to pass that form as unevaluated
data (literal) to a FUNCTION, because functions receive their
arguments evaluated.
Macros don't receive their arguments evaluated, so you don't need to
QUOTE their argument, usually. If you want to quote the arguments of
a macro, it's a hint you are wanting a function.
'(('string buf) ('string val)) --> (((quote string) buf) ((quote string) val))
(remember, --> means "evaluates to")
I don't understand what these symbols QUOTE have to do in your data
structure. What are you trying to describe with this data? I gather
that you are describing a list of parameters, each with a name and a
type. So just write it:
( ; a list
; of parameters; we'll write each parameter as
( ; a list
; containing the name of the parameter:
buf
; and the type of the parameter:
string)
( ; a list
; containing the name of the parameter:
val
; and the type of the parameter:
string))
((buf string) (val string))
Why would you need to insert symbols named QUOTE in this data structure?
I simply want to take a list of arguments, each a 2-item list, and generate
code like this:
(cffi:defcallback mbox-add-field :pointer ((self :pointer) (args :pointer))
(with-parsetuple-arg 'string buf
(with-parsetuple-arg 'string val
(cffi:foreign-funcall "PyArg_ParseTuple" :pointer args :string
"ss" :pointer buf :pointer val)
(mbox-add-field (pygetarg buf) (pygetarg val))
)
)
(py_buildvalue "s" ""))
You should indent properly your code!!!
(cffi:defcallback mbox-add-field :pointer ((self :pointer) (args :pointer))
(with-parsetuple-arg 'string buf
(with-parsetuple-arg 'string val
(cffi:foreign-funcall "PyArg_ParseTuple"
:pointer args
:string "ss"
:pointer buf
:pointer val)
(mbox-add-field (pygetarg buf) (pygetarg val))))
(py_buildvalue "s" ""))
Now we can see clearly that we have to data structures:
((buf string) (val string))
and:
(cffi:defcallback mbox-add-field :pointer ((self :pointer) (args :pointer))
(with-parsetuple-arg (quote string) buf
(with-parsetuple-arg (quote string) val
(cffi:foreign-funcall "PyArg_ParseTuple"
:pointer args
:string "ss"
:pointer buf
:pointer val)
(mbox-add-field (pygetarg buf) (pygetarg val))))
(py_buildvalue "s" ""))
and assuming that all occurences of the symbols found in the first
tree are to be substituted in the places where they occur in the
second list, we can describe the transformation with the following
patterns:
((<name> <type>)...)
==>
(cffi:defcallback mbox-add-field :pointer ((self :pointer) (args :pointer))
(with-parsetuple-arg (quote <type>) <name>
...
(cffi:foreign-funcall "PyArg_ParseTuple"
:pointer args
:string "ss"
:pointer <name>
...)
(mbox-add-field (pygetarg <name>) ...))
(py_buildvalue "s" ""))
Now, that the problem is specified, can you write a function to do
this transformation between these two data structures?
(defun gen-callback (input)
(loop
:with body = `(progn
(cffi:foreign-funcall "PyArg_ParseTuple"
:pointer args
:string "ss"
,@(loop :for (<name> <ype>) :in input
:nconc `(:pointer ,<name>)))
(mbox-add-field ,@(loop :for (<name> <type>) :in input
:collect `(pygetarg ,<name>))))
:for (<name> <type>) :in (reverse input)
:do (setf body `(with-parsetyple-arg (quote ,<type>) ,<name> ,body))
:finally (return body)))
[90]> (gen-callback '((buf string) (val integer)))
(WITH-PARSETYPLE-ARG 'STRING BUF
(WITH-PARSETYPLE-ARG 'INTEGER VAL
(PROGN
(CFFI:FOREIGN-FUNCALL "PyArg_ParseTuple" :POINTER ARGS :STRING "ss" :POINTER
BUF :POINTER VAL)
(MBOX-ADD-FIELD (PYGETARG BUF) (PYGETARG VAL)))))
Now, if you want to avoid the ' in the gen-callback call, or if you
want to have the data generated be compiled, you can call gen-callback
from a macro:
(defmacro callback (input) (gen-callback input))
[92]> (macroexpand-1 '(callback ((buf string) (val integer))))
(WITH-PARSETYPLE-ARG 'STRING BUF
(WITH-PARSETYPLE-ARG 'INTEGER VAL
(PROGN
(CFFI:FOREIGN-FUNCALL "PyArg_ParseTuple" :POINTER ARGS :STRING "ss" :POINTER
BUF :POINTER VAL)
(MBOX-ADD-FIELD (PYGETARG BUF) (PYGETARG VAL))))) ;
T
I've handled pygetarg, which looks like this:
(defmacro pygetarg(variable)
`(cffi:foreign-string-to-lisp(cffi:mem-ref ,variable :string)))
What has this to do with the wanted macros? Can't you concentrate on
the job at hand?
I couldn't figure out how to generate the code without running it, so I
created a list of the code required and stuck an 'eval' there. There, I
said it.
So you can't figure how to avoid EVAL, therefore you add one more EVAL.
Logical.
Use MACROEXPAND-1 to expand a macro!
(But first, write a function to do the job!)
--
__Pascal Bourguignon__ http://www.informatimago.com/
The rule for today:
Touch my tail, I shred your hand.
New rule tomorrow.
.
- Follow-Ups:
- Re: Help needed with macros: Brain turning to jelly
- From: Jeremy Smith
- Re: Help needed with macros: Brain turning to jelly
- References:
- Help needed with macros: Brain turning to jelly
- From: Jeremy Smith
- Help needed with macros: Brain turning to jelly
- Prev by Date: Re: beginner question on idiomatic lisp
- Next by Date: sbcl - how to get a REPL for a created thread?
- Previous by thread: Re: Help needed with macros: Brain turning to jelly
- Next by thread: Re: Help needed with macros: Brain turning to jelly
- Index(es):
Relevant Pages
|