Re: Macro-writing macro - interpreting dynamic keyword arguments for use in 2nd-level macro



In article <1193713558.885107.248830@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
Joubert Nel <joubert.nel@xxxxxxxxx> wrote:

Hi,

I'm working on a macro that does substantial lifting. I've hit a snag,
however, and even though I can see where the issue is I know that I
don't fully understand the computational reason for the failure, or
else I would know either (a) I'm trying the impossible, or (b) how to
overcome the problem.

Anyway, introduction aside, here's the issue.

I have a macro (MKINSTANCER) that can inspect a lists (one might be
called OB1) expressed in my own grammar, and based on it will
construct another macro (e.g. OB1-INSTANCER) with keyword arguments
based on the slots defined by OB1 (basically constructing an object
and setting slot values according to the keyword arguments passed to
OB1-INSTANCER).
To enhance MACX, I want it to insert logic into resulting macros that
it writes, to only process keyword arguments if the user supplied
values.

The problem is that the expressions I've written don't evaluate to the
values supplied as keyword values, but instead try to evaluate unbound
variables with the same names (symbols?) you would usually use to pick
up the values of the keyword arguments.

Here is a version of MKINSTANCER that highlights the problem:

(defmacro mkinstancer (instancer-name)
(let* ((keyw-args `((HEIGHT NIL HEIGHT-SUPPLIED-P) (WIDTH NIL WIDTH-
SUPPLIED-P)))
(keyw-args-q (mapcar #'(lambda (x) (list 'quote x)) keyw-args)))
`(defmacro ,instancer-name (&key ,@keyw-args)
`(progn
,@(mapcar #'(lambda (val)
`(princ ,(first (second val))))
(quote ,keyw-args-q))))))
..............................................................................

What this would generate when called is shown by the following
macroexpansion:

(macroexpand-1 `(mkinstancer instancer1))
(DEFMACRO INSTANCER1
(&KEY (HEIGHT () HEIGHT-SUPPLIED-P) (WIDTH () WIDTH-SUPPLIED-
P))
`(PROGN
,@(MAPCAR #'(LAMBDA (VAL) `(PRINC ,(FIRST (SECOND VAL))))
'('(HEIGHT NIL HEIGHT-SUPPLIED-P)
'(WIDTH NIL WIDTH-SUPPLIED-P)))))



You may want to expand that into this version:

(DEFMACRO INSTANCER1 (&KEY (HEIGHT () HEIGHT-SUPPLIED-P) (WIDTH () WIDTH-SUPPLIED-P))
`(PROGN
,@(MAPCAR #'(LAMBDA (VAL) `(PRINC ,(FIRST VAL)))
`((,HEIGHT NIL ,HEIGHT-SUPPLIED-P)
(,WIDTH NIL ,HEIGHT-SUPPLIED-P)))))

Your code does not reference the macro's variables. The
symbols HEIGHT, WIDTH, HEIGHT-SUPPLIED-P and HEIGHT-SUPPLIED-P
are inside literal lists.

(defmacro mkinstancer (instancer-name)
(let* ((keyw-args '((HEIGHT NIL HEIGHT-SUPPLIED-P) (WIDTH NIL WIDTH-SUPPLIED-P)))
(keyw-args-list (loop for (var default supplied-p) in keyw-args
collect `(list ,var ,default ,supplied-p))))
`(defmacro ,instancer-name (&key ,@keyw-args)
`(progn
,@(mapcar #'(lambda (val)
`(princ ,(first val)))
(list ,@keyw-args-list))))))

Check if this does what you want...

..............................................................................

I then create my "2nd-level" macro like so:

(mkinstancer instancer1)

And this has the following sample macroexpansion:
(macroexpand-1 `(instancer1 :height 45 :width 90))
(PROGN (PRINC HEIGHT) (PRINC WIDTH))

..............................................................................

I am trying to get this to be instead: "(PROGN (PRINC 45) (PRINC
90))".

Why I actually call the macro "instancer1", I get the following
backtrace (showing I'm referencing unbound variable HEIGHT):

The variable HEIGHT is unbound.
[Condition of type UNBOUND-VARIABLE]

Restarts:
0: [ABORT] Return to SLIME's top level.
1: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-
thread" {AF8C939}>)

Backtrace:
0: (SB-INT:SIMPLE-EVAL-IN-LEXENV HEIGHT #<NULL-LEXENV>)
1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (PRINC HEIGHT) #<NULL-LEXENV>)
2: (SB-IMPL::SIMPLE-EVAL-PROGN-BODY
((PRINC HEIGHT) (PRINC WIDTH))
#<NULL-LEXENV>)
3: (SB-INT:SIMPLE-EVAL-IN-LEXENV
(INSTANCER1 :HEIGHT 45 :WIDTH 90)
#<NULL-LEXENV>)
--more--

========================

I know this has been a long post but I hope I've expressed the
situation clearly enough for someone to suggest a path to
illumination.

I'm using SBCL 1.0.7 on Linux (Ubuntu Gutsy Gibbon).

Joubert

PS: In my wanderings I've experimented with different combinations of
symbol-value, find-symbol, etc. in the (mapcar) expression because I
thought the problem is a symbol lookup mismatch.
.



Relevant Pages

  • Macro-writing macro - interpreting dynamic keyword arguments for use in 2nd-level macro
    ... I'm working on a macro that does substantial lifting. ... and setting slot values according to the keyword arguments passed to ... (PROGN (PRINC HEIGHT) ... backtrace (showing I'm referencing unbound variable HEIGHT): ...
    (comp.lang.lisp)
  • Re: WHY IS JCL ALLERGIC TO LOWER CASE?
    ... so that a mixed case argment in any of JCL, TSO, IDCAMS, IEHPROGM, ... One may wish, as I do, to avoid coding much the same sequence of conditional-assembly instructions to cope with each of many of these conceptually similar situations, and for this purpose I use a sort of subroutine macro definition, imaginativelty named YESNOCHK. ... For IBM-MAIN subscribe / signoff / archive access instructions, ...
    (bit.listserv.ibm-main)
  • Re: Macro-writing macro - interpreting dynamic keyword arguments for use in 2nd-level ma
    ... and setting slot values according to the keyword arguments passed to ... second macro instead of having the first macro construct functions. ... evaluation or non-evaluation. ... backquote and put it in the part of the first macro that executes. ...
    (comp.lang.lisp)
  • Re: Scheme newbie has a porblem with recursive function
    ... applied to the evaluated operants) or a macro, ... distinguished by the syntactic keyword, ... has its standard RnRS binding. ... Scheme lets you rebind it.) ...
    (comp.lang.scheme)
  • Re: macro that writes macros
    ... (defun new-tags (&rest tags) ... you're better off having a function that constructs the PROGN ... macro expansion, so that the ordinary processor for the macro can do ... is to re-create all the bad things about FEXPRs. ...
    (comp.lang.lisp)