From: Pascal Bourguignon
Subject: Macro with syntactic tree vs. Macro as source string.
Date: 
Message-ID: <87n0e060hz.fsf@thalassa.informatimago.com>
Let's  explore what  could be  done  in other  languages to  implement
macros.  They  don't have accessible  syntactic tree, so  let's assume
there is only source strings.  After  all, even in C (actually seen in
Objective-C), it's possible at run  time to generate a string with the
source of a  function, to invoke the compiler  and to dynamically load
that function and call it.

So,  let's experiment  writting macro  that would  return a  string of
source code instead of a sexp:

[11]> (DEFMACRO DEFSTRMACRO (NAME ARGS &BODY BODY)
  (LET ((DOCSTR NIL))
    (WHEN (AND (CDR BODY) (STRINGP (CAR BODY)))
      (SETQ DOCSTR (CAR BODY)
            BODY   (CDR BODY)))
    `(DEFMACRO ,NAME ,ARGS
       ,@(IF DOCSTR (LIST DOCSTR) NIL)
       (READ-FROM-STRING (PROGN ,@BODY))))
  )
DEFSTRMACRO
[26]> (MACROEXPAND-1 
 '(DEFSTRMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
    (FORMAT NIL "(DEFUN ~A (A B)~
     (COND~
      ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
      ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
      (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
            NAME NUMBER-OP STRING-OP OPERATOR))
 )
(DEFMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
 (READ-FROM-STRING
  (PROGN
   (FORMAT NIL
    "(DEFUN ~A (A B)~
     (COND~
      ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
      ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
      (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
    NAME NUMBER-OP STRING-OP OPERATOR)))) ;
T
[27]> (DEFSTRMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
    (FORMAT NIL "(DEFUN ~A (A B)~
     (COND~
      ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
      ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
      (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
            NAME NUMBER-OP STRING-OP OPERATOR))
MAKE-COMPARISON
[28]> (MACROEXPAND-1 '(MAKE-COMPARISON BLT <  <  STRING< ))
(DEFUN BLT (A B)
 (COND ((AND (NUMBERP A) (NUMBERP B)) (BOOL (< A B)))
  ((AND (STRINGP A) (STRINGP B)) (BOOL (STRING< A B)))
  (T (ERROR "INCOMPATIBLE OPERANDS FOR ~A." '<)))) ;
T
[29]> (MAKE-COMPARISON BLT <  <  STRING< )
BLT
[30]> (SYMBOL-FUNCTION 'BLT)
#<CLOSURE BLT (A B) (DECLARE (SYSTEM::IN-DEFUN BLT))
  (BLOCK BLT
   (COND ((AND (NUMBERP A) (NUMBERP B)) (BOOL (< A B)))
    ((AND (STRINGP A) (STRINGP B)) (BOOL (STRING< A B)))
    (T (ERROR "INCOMPATIBLE OPERANDS FOR ~A." '<))))>
[31]> 



Now,  let's use  for a  while DEFSTRMACRO  instead of  DEFMACRO.  What
problem could occur?



-- 
__Pascal_Bourguignon__                   http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.

From: Alex Drummond
Subject: Re: Macro with syntactic tree vs. Macro as source string.
Date: 
Message-ID: <bia4dn$q4d$1@news7.svr.pol.co.uk>
> 
> Now,  let's use  for a  while DEFSTRMACRO  instead of  DEFMACRO.  What
> problem could occur?
>

Code represented as a string is much harder to manipulate than code
represented as a list. For example, when I was writing some macros for
currying and uncurrying functions, I wanted to create nested (lambda ...)
forms. This would have been more difficult to do if I'd had to manipulate
strings instead of sexps.

Pascal Bourguignon wrote:

> 
> Let's  explore what  could be  done  in other  languages to  implement
> macros.  They  don't have accessible  syntactic tree, so  let's assume
> there is only source strings.  After  all, even in C (actually seen in
> Objective-C), it's possible at run  time to generate a string with the
> source of a  function, to invoke the compiler  and to dynamically load
> that function and call it.
> 
> So,  let's experiment  writting macro  that would  return a  string of
> source code instead of a sexp:
> 
> [11]> (DEFMACRO DEFSTRMACRO (NAME ARGS &BODY BODY)
>   (LET ((DOCSTR NIL))
>     (WHEN (AND (CDR BODY) (STRINGP (CAR BODY)))
>       (SETQ DOCSTR (CAR BODY)
>             BODY   (CDR BODY)))
>     `(DEFMACRO ,NAME ,ARGS
>        ,@(IF DOCSTR (LIST DOCSTR) NIL)
>        (READ-FROM-STRING (PROGN ,@BODY))))
>   )
> DEFSTRMACRO
> [26]> (MACROEXPAND-1
>  '(DEFSTRMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
>     (FORMAT NIL "(DEFUN ~A (A B)~
>      (COND~
>       ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
>       ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
>       (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
>             NAME NUMBER-OP STRING-OP OPERATOR))
>  )
> (DEFMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
>  (READ-FROM-STRING
>   (PROGN
>    (FORMAT NIL
>     "(DEFUN ~A (A B)~
>      (COND~
>       ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
>       ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
>       (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
>     NAME NUMBER-OP STRING-OP OPERATOR)))) ;
> T
> [27]> (DEFSTRMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
>     (FORMAT NIL "(DEFUN ~A (A B)~
>      (COND~
>       ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
>       ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
>       (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
>             NAME NUMBER-OP STRING-OP OPERATOR))
> MAKE-COMPARISON
> [28]> (MACROEXPAND-1 '(MAKE-COMPARISON BLT <  <  STRING< ))
> (DEFUN BLT (A B)
>  (COND ((AND (NUMBERP A) (NUMBERP B)) (BOOL (< A B)))
>   ((AND (STRINGP A) (STRINGP B)) (BOOL (STRING< A B)))
>   (T (ERROR "INCOMPATIBLE OPERANDS FOR ~A." '<)))) ;
> T
> [29]> (MAKE-COMPARISON BLT <  <  STRING< )
> BLT
> [30]> (SYMBOL-FUNCTION 'BLT)
> #<CLOSURE BLT (A B) (DECLARE (SYSTEM::IN-DEFUN BLT))
>   (BLOCK BLT
>    (COND ((AND (NUMBERP A) (NUMBERP B)) (BOOL (< A B)))
>     ((AND (STRINGP A) (STRINGP B)) (BOOL (STRING< A B)))
>     (T (ERROR "INCOMPATIBLE OPERANDS FOR ~A." '<))))>
> [31]>
> 
> 
> 
> Now,  let's use  for a  while DEFSTRMACRO  instead of  DEFMACRO.  What
> problem could occur?
> 
> 
> 
From: Pascal Bourguignon
Subject: Re: Macro with syntactic tree vs. Macro as source string.
Date: 
Message-ID: <878ypjf4zn.fsf@thalassa.informatimago.com>
Alex Drummond <ยทยทยทยท@abingdon74.freeserve.co.uk> writes:

> > 
> > Now,  let's use  for a  while DEFSTRMACRO  instead of  DEFMACRO.  What
> > problem could occur?
> >
> 
> Code represented as a string is much harder to manipulate than code
> represented as a list. For example, when I was writing some macros for
> currying and uncurrying functions, I wanted to create nested (lambda ...)
> forms. This would have been more difficult to do if I'd had to manipulate
> strings instead of sexps.

Of  course, I  agree, since  I'm  using Lisp.   The point  is that  in
language that  don't represent programs as lists,  that actually don't
have any representation for the  program, either you have to represent
it as  a source string, or you  have to build your  own data structure
(ie.   rewritting a lisp).   So, for  them, let's  make it  simple and
assume that they'll  write macros as string and  thus avoid any syntax
issue.

Perhaps the main  problem is actually to have  code run at compilation
time?

Such a macro:
    
    (DEFSTRMACRO MAKE-COMPARISON (NAME OPERATOR NUMBER-OP STRING-OP)
         (FORMAT NIL "(DEFUN ~A (A B)~
          (COND~
           ((AND (NUMBERP A) (NUMBERP B)) (BOOL (~A A B)))~
           ((AND (STRINGP A) (STRINGP B)) (BOOL (~A A B)))~
           (T (ERROR \"INCOMPATIBLE OPERANDS FOR ~~A.\" '~A)))))"
                 NAME NUMBER-OP STRING-OP OPERATOR))

would be written in C as:

    macro char* make_comparison(char* name,char* operator,
                                char* number_op,char* string_op)
    {
        char* buffer=malloc(compute_size_for_comparison(name,operator,
                                                  number_op,string_op));
        sprintf(buffer,
                "bool %s (object* a,object* b)\n"
                "{ if(object_is_number(a)&&object_is_number(b)){\n"
                "    return(%s(a,b));\n"
                "  }else if(object_is_string(a)&&object_is_string(b)){\n"
                "    return(%s(a,b));\n"
                "  }else{ error(\"Incompatible operands for %s\\n\",%s);\n"
                "  }\n"
                "}\n",
                name,number_op,string_op,operator);
        return(buffer);
    }

Now the question  is how does the compiler compile,  link and run this
macro function at compilation time?

I assume  the problem  is similar  in python or  whatever, as  soon as
there's no representation of the program (along with an eval function)
available both at compile time and at run time.


-- 
__Pascal_Bourguignon__                   http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.