User Tools

A PCRE internal error occured. This might be caused by a faulty plugin

====== Macro DEFMACRO ====== ====Syntax==== * **defmacro** //name lambda-list <nowiki>[[</nowiki>declaration''*'' | documentation<nowiki>]]</nowiki> form''*''// → //name// ====Arguments and Values==== * //name// - a //[[CL:Glossary:symbol]]//. * //lambda-list// - a //[[CL:Glossary:macro lambda list]]//. * //declaration// - a **[[CL:Symbols:declare]]** //[[CL:Glossary:expression]]//; not evaluated. * //documentation// - a //[[CL:Glossary:string]]//; not evaluated. * //form// - a //[[CL:Glossary:form]]//. ====Description==== Defines //name// as a //[[CL:Glossary:macro]]// by associating a //[[CL:Glossary:macro function]]// with that //name// in the global environment. The //[[CL:Glossary:macro function]]// is defined in the same //[[CL:Glossary:lexical environment]]// in which the **[[CL:Macros:defmacro]]** //[[CL:Glossary:form]]// appears. The parameter variables in //lambda-list// are bound to destructured portions of the macro call. The expansion function accepts two arguments, a //[[CL:Glossary:form]]// and an //[[CL:Glossary:environment]]//. The expansion function returns a //[[CL:Glossary:form]]//. The body of the expansion function is specified by //forms//. //Forms// are executed in order. The value of the last //form// executed is returned as the expansion of the //[[CL:Glossary:macro]]//. The body //forms// of the expansion function (but not the //lambda-list//) are implicitly enclosed in a //[[CL:Glossary:block]]// whose name is //name//. The //lambda-list// conforms to the requirements described in {\secref\MacroLambdaLists}. //Documentation// is attached as a //[[CL:Glossary:documentation string]]// to //name// (as kind **[[CL:Special Operators:function]]**) and to the //[[CL:Glossary:macro function]]//. **[[CL:Macros:defmacro]]** can be used to redefine a //[[CL:Glossary:macro]]// or to replace a //[[CL:Glossary:function]]// definition with a //[[CL:Glossary:macro]]// definition. Recursive expansion of the //[[CL:Glossary:form]]// returned must terminate, including the expansion of other //[[CL:Glossary:macro|macros]]// which are //[[CL:Glossary:subform|subforms]]// of other //[[CL:Glossary:form|forms]]// returned. The consequences are undefined if the result of fully macroexpanding a //[[CL:Glossary:form]]// contains any //[[CL:Glossary:circular]]// //[[CL:Glossary:list structure]]// except in //[[CL:Glossary:literal object|literal objects]]//. If a **[[CL:Macros:defmacro]]** //[[CL:Glossary:form]]// appears as a //[[CL:Glossary:top level form]]//, the //[[CL:Glossary:compiler]]// must store the //[[CL:Glossary:macro]]// definition at compile time, so that occurrences of the macro later on in the file can be expanded correctly. Users must ensure that the body of the //[[CL:Glossary:macro]]// can be evaluated at compile time if it is referenced within the //[[CL:Glossary:file]]// being //[[CL:Glossary:compiled]]//. ====Examples==== <blockquote> (defmacro mac1 (a b) "Mac1 multiplies and adds" `([[CL:Functions:math-add|+]] ,a ([[CL:Functions:math-multiply|*]] ,b 3))) <r>MAC1 </r> (mac1 4 5) <r>19 </r> ([[CL:Functions:documentation]] 'mac1 '[[CL:Types:function]]) <r>"Mac1 multiplies and adds"</r> (defmacro mac2 (&optional (a 2 b) (c 3 d) &rest x) `'(,a ,b ,c ,d ,x)) <r>MAC2</r> (mac2 6) <r>(6 [[CL:Constant Variables:t|T]] 3 [[CL:Constant Variables:nil|NIL]] [[CL:Constant Variables:nil|NIL]])</r> (mac2 6 3 8) <r>(6 [[CL:Constant Variables:t|T]] 3 [[CL:Constant Variables:t|T]] (8))</r> (defmacro mac3 (&whole r a &optional (b 3) &rest x &key c (d a)) `'(,r ,a ,b ,c ,d ,x)) <r>MAC3</r> (mac3 1 6 :d 8 :c 9 :d 10) <r>((MAC3 1 6 :D 8 :C 9 :D 10) 1 6 9 8 (:D 8 :C 9 :D 10))</r> </blockquote> The stipulation that an embedded //[[CL:Glossary:destructuring lambda list]]// is permitted only where //[[CL:Glossary:ordinary lambda list]]// syntax would permit a parameter name but not a //[[CL:Glossary:list]]// is made to prevent ambiguity. For example, the following is not valid: <blockquote> (defmacro loser (x &optional (a b &rest c) &rest z) ...) </blockquote> because //[[CL:Glossary:ordinary lambda list]]// syntax does permit a //[[CL:Glossary:list]]// following ''&optional''; the list ''(a b &rest c)'' would be interpreted as describing an optional parameter named ''a'' whose default value is that of the form ''b'', with a supplied-p parameter named ''&rest'' (not valid), and an extraneous symbol ''c'' in the list (also not valid). An almost correct way to express this is <blockquote> (defmacro loser (x &optional ((a b &rest c)) &rest z) ...) </blockquote> The extra set of parentheses removes the ambiguity. However, the definition is now incorrect because a macro call such as ''(loser (car pool))'' would not provide any argument form for the lambda list ''(a b &rest c)'', and so the default value against which to match the //[[CL:Glossary:lambda list]]// would be **[[CL:Constant Variables:nil]]** because no explicit default value was specified. The consequences of this are unspecified since the empty list, **[[CL:Constant Variables:nil]]**, does not have //[[CL:Glossary:form|forms]]// to satisfy the parameters ''a'' and ''b''. The fully correct definition would be either <blockquote> (defmacro loser (x &optional ((a b &rest c) '(nil nil)) &rest z) ...) </blockquote> or <blockquote> (defmacro loser (x &optional ((&optional a b &rest c)) &rest z) ...) </blockquote> These differ slightly: the first requires that if the macro call specifies ''a'' explicitly then it must also specify ''b'' explicitly, whereas the second does not have this requirement. For example, <blockquote> (loser ([[CL:Functions:car]] pool) (([[CL:Functions:math-one-plus|1+]] x))) </blockquote> would be a valid call for the second definition but not for the first. <blockquote> (defmacro dm1a (&whole x) `',x) <r>DM1A</r> ([[CL:Functions:macroexpand]] '(dm1a)) <r>([[CL:Special Operators:quote|QUOTE]] (DM1A))</r> ([[CL:Functions:macroexpand]] '(dm1a a)) <e>Error: while parsing arguments to DEFMACRO DM1A: exactly 0 expected, but got 1.</e> (defmacro dm1b (&whole x a &optional b) `'(,x ,a ,b)) <r>DM1B</r> ([[CL:Functions:macroexpand]] '(dm1b)) <e>Error: while parsing arguments to DEFMACRO DM1A: between 1 and 2 expected, but got 0.</e> ([[CL:Functions:macroexpand]] '(dm1b q)) <r>([[CL:Special Operators:quote|QUOTE]] ((DM1B Q) Q NIL))</r> ([[CL:Functions:macroexpand]] '(dm1b q r)) <r>([[CL:Special Operators:quote|QUOTE]] ((DM1B Q R) Q R))</r> ([[CL:Functions:macroexpand]] '(dm1b q r s)) <e>Error: while parsing arguments to DEFMACRO DM1A: between 1 and 2 expected, but got 3.</e> (defmacro dm2a (&whole form a b) `'(form ,form a ,a b ,b)) ([[CL:Functions:macroexpand]] '(dm2a x y)) <r>([[CL:Special Operators:quote|QUOTE]] (FORM (DM2A X Y) A X B Y)) T</r> (dm2a x y) <r>(FORM (DM2A X Y) A X B Y)</r> (defmacro dm2b (&whole form a (&whole b (c . d) &optional (e 5)) &body f &environment env) ``(,',form ,,a ,',b ,',([[CL:Functions:macroexpand]] c env) ,',d ,',e ,',f)) ([[CL:Functions:macroexpand]] '(dm2b x1 ((([[CL:Macros:incf]] x2) x3 x4)) x5 x6)) <r>(LIST* '(DM2B X1 ((([[CL:Macros:incf|INCF]] X2) X3 X4)) X5 X6) X1 '(((([[CL:Macros:incf|INCF]] X2) X3 X4)) ([[CL:Macros:setf|SETF]] X2 ([[CL:Functions:math-one-plus|1+]] X2)) (X3 X4) 5 (X5 X6))) [[CL:Constant Variables:T]] </r> </blockquote> In the above example, note that because backquote is involved, implementations may differ slightly in the nature (though not the functionality) of the expansion. <blockquote> ([[CL:Special Operators:let]] ((x1 5)) ([[CL:Special Operators:macrolet]] ((segundo (x) `([[CL:Functions:cadr]] ,x))) (dm2b x1 (((segundo x2) x3 x4)) x5 x6))) <r>((DM2B X1 (((SEGUNDO X2) X3 X4)) X5 X6) 5 (((SEGUNDO X2) X3 X4)) (CADR X2) (X3 X4) 5 (X5 X6)) </r> </blockquote> ====Affected By==== None. ====Exceptional Situations==== None. ====See Also==== **[[CL:Macros:define-compiler-macro|Macro DEFINE-COMPILER-MACRO]]**, **[[CL:Macros:destructuring-bind|Macro DESTRUCTURING-BIND]]**, **[[CL:Functions:documentation|Generic Function DOCUMENTATION]]**, **[[CL:Functions:macroexpand|Function MACROEXPAND]]**, **[[CL:Variables:star-macroexpand-hook-star|Variable *MACROEXPAND-HOOK*]]**, **[[CL:Special Operators:macrolet|Special Operator MACROLET]]**, **[[CL:Functions:macro-function|Function MACRO-FUNCTION]]**, {\secref\Evaluation}, {\secref\Compilation}, {\secref\DocVsDecls} ====Notes==== None. \issue{COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY} \issue{DEFMACRO-LAMBDA-LIST:TIGHTEN-DESCRIPTION} \issue{DEFINE-COMPILER-MACRO:X3J13-NOV89} \issue{DECLS-AND-DOC} \issue{DEFINING-MACROS-NON-TOP-LEVEL:ALLOW} \issue{FLET-IMPLICIT-BLOCK:YES} \issue{DEFMACRO-BLOCK-SCOPE:EXCLUDES-BINDINGS} \issue{DOCUMENTATION-FUNCTION-BUGS:FIX} \issue{RECURSIVE-DEFTYPE:EXPLICITLY-VAGUE}