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?
>
>
>
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.