Macros calling macros

lisp

    Next

  • 1. When CANNOT use 'first'/'rest' in place of 'car'/'cdr'?
    If I'm not mistaken, 'first' and 'rest' seem like modern user friendly replacements for 'car' and 'cdr'. Is it true that car and cdr are only in Common LISP to be able to run ancient LISP code? Is there any time I cannot use 'first' and 'rest' instead?/ Chris
  • 2. Klassic Keyboards (was Lisp keyboard)
    XXXX@XXXXX.COM wrote: > What were the other letters on the top row? I have read that the first > try was something in alphabetical order but that some common bigraphs, > like ed, were too near each other, corresponding to print bars that > jamed because of their proximity. After that there was an atempt to > alternate these between right and left sides or under the same finger. > You use a keyboard to type your posts to this NG, other than that my > post dosn't belong here. After doing some Googleing, it seems that the original keyboard was designed with only two rows, with A-M on the top and N-Z on the bottom. I guess both space constraints and jamming caused the monstrosity that is QWERTY. I type on Dvorak; it feels much much better. -- MJF

Macros calling macros

Postby dc » Wed, 05 Nov 2008 15:24:42 GMT

Hi,

I have written a couple of small macros that does some text output and
needs to indent. It kind of looks like the following :-

(defmacro with-indent (&rest args)
  `(combine
     (indent+) ,@args (indent-)))

(defmacro gen-block (block-type block-name &rest args)
  `(combine
      (gen-begin block-type block-name)
      (with-indent ,@args)
      (gen-end block-type)))

; indent+/- just alter a variable which is indent level. gen-begin/end
make "begin/end blah" strings.

On the surface of it, this works fine. I can get gen-block to make
begin/end statements for home made scripting languages (which is what
this is for) by doing

(gen-block "block" "test block"
   (print "first line") (print "second line"))

...and getting

block "test block"
  print "first line"
  print "second line"
end block

However, if I do

(gen-block "block" "outer block" (gen-block "block" "inner block")
(print "hello"))

I get

block "outer block"
  block "inner block"     ; Everything is okay so far.
    print "hello"
    end block                ; Here is the problem.
end block

The indent level gets set and passed on to the next macro expansion
and I thought perhaps someone here might know of a way of getting the
desired result which would allow for unlimited nesting without mucking
up the trailing indents.

I'm wanting to use macros because I'll be transforming the statements
passed in.

Any ideas appreciated (would generating a closure with it's own level
around each block help?)

Cheers
DC

Re: Macros calling macros

Postby Alex Mizrahi » Wed, 05 Nov 2008 18:33:30 GMT

 d> Any ideas appreciated (would generating a closure with it's own level
 d> around each block help?)

i guess your problem is that you're using variable *indent* in your macros.
do not do that -- use it only at run time, and it will be fine.

it is not a case where you need macros calling macros -- macros can
just do syntatic conversion for you, but you can do all computatations (such 
as computing indent amount)
at runtime with ordinary functions. 



Re: Macros calling macros

Postby budden » Thu, 06 Nov 2008 01:51:24 GMT

Hi, dc
 I used to do something similar, and had a similar error.
I thing this is not related to macros. Anyway, you might use
(macroexpand-1 'your-code) too see the macroexpanded code.
 It looks like a error in a logic. E.g., sometimes you're swapping
generation of indentation and generation of a newline (this was in my
case). It is very easy to err this way.


Re: Macros calling macros

Postby William James » Thu, 06 Nov 2008 05:19:11 GMT


> (defmacro gen-block (block-type block-name &rest arg>)
> `(comb>ne
> (gen-begin block-type block>name)
> (with-inden> ,@args)
> (gen-end b>oc>-type)))
>
> ; indent+/- just alter a variable which is indent level. g>n-begin/end
> make "begin/end bl>h">strings.
>
> On the surface of it, this works fine. I can get gen-b>ock to make
> begin/end statements for home made scripting languages (w>ich is what
> this is f>r)>by doing
>
> (gen-block "block" >test block"
> print "first line") (print ">ec>nd line"))
>
> >..>nd getting
>
> bloc> "test block"
> pri>t "first line"
> pri>t "second li>e">
> end block
>
> >ow>ver, if I do
>
> (gen-block "block" "outer block" (gen-block "block> "inner block")
> >pr>nt "hell>")>
>
> I get
>
> blo>k "outer block"
> block "inner block" ; Everyth>ng is okay so far.>
> print "hello"
> end block >  He>e >s the problem.
> end block
>
> The indent level gets set and passed>on to the next macro expansion
> and I thought perhaps someone here mig>t know of a way of getting the
> desired result which would allow for un>imited nesting without mucking
> up the trailing indents.

Macros aren't needed.  A single function
does it all.

Ruby:

def gen_block type, name, *stuff
  [ "#{type} \"#{name}\"",
    stuff.flatten.map{|x| "  #{x}"},
  "end #{type}" ].flatten
end

puts gen_block("block", "outer block",'print "hello"')

puts gen_block("block", "outer block",
  gen_block("block","inner block",'print "hello"'))

--- output ---
block "outer block"
  print "hello"
end block
block "outer block"
  block "inner block"
    print "hello"
  end block
end block

Re: Macros calling macros

Postby Raymond Wiker » Thu, 06 Nov 2008 06:02:25 GMT

William James < XXXX@XXXXX.COM > writes:



>> (defmacro gen-block (block-type block-name &rest arg>>
>> `(comb>>e
>> (gen-begin block-type block>>ame)
>> (with-inden>>,@args)
>> (gen-end b>>ck>>ype)))
>>
>> ; indent+/- just alter a variable which is indent level. g>>-begin/end
>> make "begin/end bl>>" >>rings.
>>
>> On the surface of it, this works fine. I can get gen-b>>ck to make
>> begin/end statements for home made scripting languages (w>>ch is what
>> this is f>>) >> doing
>>
>> (gen-block "block" >>est block"
>> print "first line") (print ">>co>> line"))
>>
>> >>.a>> getting
>>
>> bloc>>"test block"
>> pri>> "first line"
>> pri>> "second lin>>
>>
>> >>we>>r, if I do
>>
>> (gen-block "block" "outer block" (gen-block "block>>"inner block")
>> >>ri>> "hello">>
>> I get
>>
>> blo>> "outer block"
>> block "inner block" ; Everyth>>g is okay so far.
>>> print "hello"
>> end block >> Her>>is>>he problem.
>> end block
>>
>> The indent level gets set and passed>>n to the next macro expansion
>> and I thought perhaps someone here mig>> know of a way of getting the
>> desired result which would allow for un>>mited nesting without mucki>g
>>> up the trailing indents.
>
> Macros ar>n't needed.  A >in>le funct>on>
> does it all.
>
> Ruby:
>
> d>f gen_block type, name, *stuf>
>   [ "#{type} \"#{name}\"",
>     s>uff.flatten.map{|x| "  #{x}">,
>  >"e>d #{type}" ].flatten
> end
>
> puts gen_block("block",>"o>ter block",'print "hello"')
>
> puts ge>_block("block", "outer block",
>   gen_block("block",>in>er block",'print >hello"'))
>
> --- ou>put ---
> block ">uter block"
>>   print "hello"
> e>d block
> block "outer >lock"
>   block "in>er block"
>  >  print "hello"
>   end block
> end block

	Hey, Einstein... you may not have noticed, but this is
comp.lang.lisp, so posting Ruby code is not likely to help the OP. 

Re: Macros calling macros

Postby Tamas K Papp » Thu, 06 Nov 2008 06:12:15 GMT




Hey Heisenberg,

Most of us figured out how to filter him and his ilk out using our 
newsreaders, so we would not see a single post from them.  But some 
genius always has to reply to these idiots.

Tamas

Re: Macros calling macros

Postby Andrew Main » Thu, 06 Nov 2008 18:06:49 GMT




You assume that William James is trying to help people. You're not the first 
person to tell him to stop with the ruby code in comp.lang.lisp

Re: Macros calling macros

Postby Kaz Kylheku » Fri, 07 Nov 2008 08:51:46 GMT




>> block "inner block" ; Everything is okay so far>>
>> print "hel>>"
>> end block  Here is>>he problem.
>>> >>d block
>>
>> The indent level gets set and passed on to the next ma>>o expansion
>> and I thought perhaps someone here might know of a way o>>getting the
>> desired result which would allow for unlimited nesting wi>>out mucking
>> up the trai>in> indents.
>
> Macros aren't needed.  A si>gle function
>>do>s it all>
> Ruby:
>
> def gen_block type,>name, *stuff
>   [ "#{type} >"#{name}\"",
>     stuff.flatten.map{|>| "  #{x}"},
>   "end #{typ>}" ].f>at>en
> end
>
> puts gen_block("block", "outer block",'print "hello"')

But the input to the Lisp macro is this code:

  (gen-block "block" "outer block" (print "hello"))

This transliterates to Ruby like this:

  gen_block("block", "outer block", print("hello"))

Part of the problem is to take syntax like   print("hello")  expression and
destructure it by pulling out the print and "hello" atoms.  But in your Ruby,
you have cheated: you have 'print "hello"' as a string literal.

Can you make it work using the Ruby expression?

Here are two test cases:

  expression:

    gen_block("block", "outer block", print("hello"))

  output:

    block "block"
      print "hello"
    end block


  expression:

    gen_block("block", "outer block", 
              gen_block("foo", "inner", return("hello")))

  output:

    block "outer block"
      foo "inner"
         return "hello"
      end foo
    end block

Teach us, Ruby master.

Similar Threads:

1.Macrology: Macro for calling macro defcallback (OpenMCL)

Hi all:

I want to define a macro to call the defcallback macro in OpenMCL. 
I assume it's my basic knowledge of macrology and not a problem of
a specific implementation.

So, any hints on the following non-working source code is 
appreciated!

#1: Definition of the DEFCALLBACK macro in OpenMCL:

Macro  DEFCALLBACK 

Syntax:  defcallback name ({arg-type-specifier var}*   
                          &optional result-type-specifier)   
                          &body   body 

#2: Working example from OpenMCL's example source code

(ccl::defcallback reshape-cb (:int w :int h)
    (format t "reshape-cb: w=~D h=~D~%" w h))


#3: My macro:

(defmacro ff-defun-callable (call-convention result-type name args &body body)
  (declare (ignorable result-type))
  (declare (ignorable call-convention))
  `(ccl:defcallback ,name
	            ,(list args)
                    ,@body))

Problem/error I get is:

Unknown foreign type: (:VOID)
   [Condition of type SIMPLE-ERROR]

Backtrace:
  0: (CCL::%PARSE-FOREIGN-TYPE '((:VOID)))
  1: (CCL::PARSE-FOREIGN-TYPE '(:VOID))
  2: (CCL::FOREIGN-TYPE-TO-REPRESENTATION-TYPE '((:VOID)))
  3: (DEFINE-CALLBACK 'CL-OPENGL::MGWCLOSE '((:VOID)) '((PRINT "closing callback entered")) #<CCL::LEXICAL-ENVIRONMENT #x69C5BE6>)
      Locals:
        CCL::NAME = CL-OPENGL::MGWCLOSE
        CCL::ARGS = ((:VOID))
        CCL::BODY = ((PRINT "closing callback entered"))
        CCL::ENV = #<CCL::LEXICAL-ENVIRONMENT #x69C5BE6>
        CCL::STACK-WORD = #:G24663
        CCL::STACK-PTR = #:G24664
        CCL::RETURN-TYPE = #<VALUE-CELL (:VOID) #x69D259E>
        CCL::WOI = #<VALUE-CELL NIL #x69D2596>
        CCL::MONITOR = #<VALUE-CELL NIL #x69D258E>
        CCL::DYNAMIC-EXTENT-NAMES = #<VALUE-CELL NIL #x69D2586>
        CCL::ERROR-RETURN = #<VALUE-CELL NIL #x69D257E>
      [No catch-tags]

So, I know I have to get rid of the args being passed as a list - 
or that's what I assume, anyway. Is that true?

When passing ,args without being a list I get another error indicating that passing the args and the name of the callback got mixed up. So...?????

Thx for any help here! If I should provide more info pls tell me!

Frank

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

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)))))

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

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.

3.Macro question (Guile define-macro)

4.macros within macros

L.S.,

Suppose I have a macro M1 that defines a macro. Lets define
a new macro using this macro:

(M1 new+ (number? number?) +)

Now, suppose I'd like to redefine the new+ macro, using the
previous definition of of itself:

(M1 new+ (string? number?) 
   (lamda (a b) (string-append a (number->string b))))

At this point, I'd like to see:

(new+ 2 3) -> 5
(new+ "a" 2) -> "a2"

I have an implementation, which is about:

(M1 new+ (number? number?) +)
(M1 newnew+ new+ (string? number?) 
   (lamda (a b) (string-append a (number->string b))))

But this is not what I'm trying to do. 

Can this be done using R5RS macro definitions?

Best regards,

Hans

5.expanding macros and passing the results to other macros

Hi,

I'm messing about with the PLT Scheme parser tools (just the lexer at 
the moment). My problem isn't specific to that though, it's getting my 
head around all the macro expansion that's going on. I don't think I'm 
using the quasiquote properly (too many commas).

For anyone that hasn't used the lexer, it looks a little like this:

  (lexer
    ("a"   <a-rule>)
    ("b"   <b-rule>))

and it's a complex macro (so a noob like me has no chance of tracing 
through it).

I want to lex a collection of keywords, and have a separate symbol token 
for each one. This is going to give code like:

  (lexer
    ("keyword1"   'token-keyword1)
    ("keyword2"   'token-keyword2)
    ("keyword3"   'token-keyword3)
    ("keyword4"   'token-keyword4)
    ...
    ; some non-keyword rules
    )

You can probably see where I'm going with this already, but I'd like to 
replace the long list with something more like:


  (lexer
    (map make-keyword-rule keywords)
    ...
    ; some non-keyword rules
    )

Using:

(define (string->keyword-token keyword-string)
   (string->symbol (string-append "token-" keyword-string)))

(define (make-keyword-rule keyword-string)
   `(,keyword-string (',(string->keyword-token keyword-string))))


But I just can't figure it. All I'm doing is expanding to one form that 
needs splicing into another before being transformed again by the lexer 
macro. OK, that doesn't sound so simple now I've typed it out loud.

So, is it possible? Is it just a case of getting me quotes in a tangle?

Thanks in advance,
pt.

6. SRFI-46: Ellipsis in Macro-Generating SYNTAX-RULES Macros

7. Macros in Macros in Gambit

8. Macro language design. Was: The Advantage of Macros



Return to lisp

 

Who is online

Users browsing this forum: No registered users and 61 guest