115 lines
22 KiB
HTML
115 lines
22 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<title>CLiki: call-next-macro</title>
|
||
|
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
|
||
|
href="https://www.cliki.net/site/feed/article.atom?title=call-next-macro">
|
||
|
<link rel="stylesheet" href="static/css/style.css">
|
||
|
<link rel="stylesheet" href="static/css/colorize.css">
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<span class="hidden">CLiki - call-next-macro</span>
|
||
|
<div id="content"><div id="content-area"><div id="article-title">call-next-macro</div><div id="article">Here's a <a href="macro example.html" class="category">macro example</a> that may be less of a headache to understand than <a href="rebinding.html" class="internal">rebinding</a>. It provides a way for a local macro definition to defer to the "next" macro definition under the same name. In this context, "next" means the <a href="https://www.cliki.net/site/HyperSpec/Body/sec_3-1-5.html">lexically exterior</a> definition, or else the global definition, if there is one (obtained via <a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="hyperspec">macro-function</a>). This is by analogy with <a href="https://www.cliki.net/site/HyperSpec/Body/locfun_call-next-method.html" class="hyperspec">call-next-method</a> and <a href="https://www.cliki.net/site/HyperSpec/Body/locfun_next-method-p.html" class="hyperspec">next-method-p</a> in method definitions.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_eval-when.html" class="symbol"><i><span class="symbol">eval-when</span></i></a> <span class="paren2">(<span class="nonparen"><span class="keyword">:compile-toplevel</span> <span class="keyword">:load-toplevel</span> <span class="keyword">:execute</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> get-macro <span class="paren3">(<span class="nonparen">name macro-functions &optional errorp</span>)</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren4">(<span class="nonparen"><span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_carcm_cdr_darcm_cddddr.html" class="symbol">cdr</a> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_assoccm_a_assoc-if-not.html" class="symbol">assoc</a> name macro-functions</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_return-from.html" class="symbol"><i><span class="symbol">return-from</span></i></a> get-macro <a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a></span>)</span></span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> errorp <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_error.html" class="symbol">error</a> <span class="string">"No macro definition for ~S."</span> name</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
|
||
|
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_eval-when.html" class="symbol"><i><span class="symbol">eval-when</span></i></a> <span class="paren2">(<span class="nonparen"><span class="keyword">:compile-toplevel</span> <span class="keyword">:load-toplevel</span> <span class="keyword">:execute</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> macro-lambda-list <span class="paren3">(<span class="nonparen">lambda-list whole env</span>)</span>
|
||
|
<span class="string">"Ensure &whole and &environment in LAMBDA-LIST."</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_eq.html" class="symbol">eq</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">first</a> lambda-list</span>)</span> '&whole</span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> whole <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">second</a> lambda-list</span>)</span></span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> lambda-list <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_carcm_cdr_darcm_cddddr.html" class="symbol">cddr</a> lambda-list</span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> with env-p = <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a>
|
||
|
for <span class="paren4">(<span class="nonparen">element . tail</span>)</span> on lambda-list
|
||
|
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_eq.html" class="symbol">eq</a> element '&environment</span>)</span>
|
||
|
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> env-p <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a> env <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_carcm_cdr_darcm_cddddr.html" class="symbol">car</a> tail</span>)</span></span>)</span>
|
||
|
finally <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">unless</a> env-p
|
||
|
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> lambda-list <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_listcm_listst.html" class="symbol">list*</a> '&environment env lambda-list</span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> lambda-list <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_listcm_listst.html" class="symbol">list*</a> '&whole whole lambda-list</span>)</span></span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_return.html" class="symbol">return</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_values.html" class="symbol">values</a> lambda-list whole env</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
|
||
|
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> macrolet+ <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">&rest macro-definitions</span>)</span> &body body &environment environment</span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> with whole = <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_gensym.html" class="symbol">gensym</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> 'whole</span>)</span></span>)</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_and.html" class="symbol">and</a> env = <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_gensym.html" class="symbol">gensym</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> 'environment</span>)</span></span>)</span>
|
||
|
for <span class="paren3">(<span class="nonparen">name lambda-list . macro-body</span>)</span> in macro-definitions
|
||
|
for <a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a> = <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a> name environment</span>)</span>
|
||
|
collect <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_cons.html" class="symbol">cons</a> name <a href="https://www.cliki.net/site/HyperSpec/Body/acc_macro-function.html" class="symbol">macro-function</a></span>)</span> into old-macro-functions
|
||
|
collect <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_multiple-value-bind.html" class="symbol">multiple-value-bind</a> <span class="paren4">(<span class="nonparen">lambda-list whole env</span>)</span>
|
||
|
<span class="paren4">(<span class="nonparen">macro-lambda-list lambda-list whole env</span>)</span>
|
||
|
`<span class="paren4">(<span class="nonparen">,name ,lambda-list
|
||
|
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_fletcm_scm_macrolet.html" class="symbol"><i><span class="symbol">flet</span></i></a> <span class="paren6">(<span class="nonparen"><span class="paren1">(<span class="nonparen">next-macro-p <span class="paren2">(<span class="nonparen"></span>)</span>
|
||
|
<span class="string">"Return true if there is a next macro."</span>
|
||
|
<span class="paren2">(<span class="nonparen">get-macro ',name ',old-macro-functions</span>)</span></span>)</span>
|
||
|
<span class="paren1">(<span class="nonparen">call-next-macro <span class="paren2">(<span class="nonparen">&rest macro-arguments &aux <span class="paren3">(<span class="nonparen">,whole ,whole</span>)</span></span>)</span>
|
||
|
<span class="string">"Call the next (outer) MACRO-FUNCTION, or else signal an error."</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> macro-arguments <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> ,whole <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_listcm_listst.html" class="symbol">list*</a> ',name macro-arguments</span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">next-macro <span class="paren5">(<span class="nonparen">get-macro ',name ',old-macro-functions <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_funcall.html" class="symbol">funcall</a> <a href="https://www.cliki.net/site/HyperSpec/Body/var_stmacroexpand-hookst.html" class="symbol"><span class="special">*macroexpand-hook*</span></a> next-macro ,whole ,env</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/sym_declare.html" class="symbol">declare</a> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/dec_dynamic-extent.html" class="symbol">dynamic-extent</a> #'next-macro-p</span>)</span></span>)</span>
|
||
|
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/sym_declare.html" class="symbol">declare</a> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/dec_dynamic-extent.html" class="symbol">dynamic-extent</a> #'call-next-macro</span>)</span></span>)</span>
|
||
|
,@macro-body</span>)</span></span>)</span></span>)</span> into new-macro-definitions
|
||
|
<span class="comment">;; Now each macro definition can use CALL-NEXT-MACRO.
|
||
|
</span> finally <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_return.html" class="symbol">return</a> `<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_fletcm_scm_macrolet.html" class="symbol"><i><span class="symbol">macrolet</span></i></a> ,new-macro-definitions
|
||
|
,@body</span>)</span></span>)</span></span>)</span></span>)</span></span></div><p><h2>Quick example</h2><p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen">macrolet+ <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">foo <span class="paren4">(<span class="nonparen">x</span>)</span> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_numberp.html" class="symbol">numberp</a> x</span>)</span> <span class="string">"It's a number."</span> <span class="paren5">(<span class="nonparen">call-next-macro</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen">macrolet+ <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">foo <span class="paren5">(<span class="nonparen">x</span>)</span> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_eql.html" class="symbol">eql</a> x 7</span>)</span> <span class="string">"Lucky."</span> <span class="paren6">(<span class="nonparen">call-next-macro</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_values.html" class="symbol">values</a> <span class="paren4">(<span class="nonparen">foo 12</span>)</span> <span class="paren4">(<span class="nonparen">foo 13</span>)</span> <span class="paren4">(<span class="nonparen">foo 1234567890</span>)</span> <span class="paren4">(<span class="nonparen">foo 7</span>)</span></span>)</span></span>)</span></span>)</span></span></div><p>Evaluating the above gives the values:<p><div class="code"><span class="nonparen">"It's a number."
|
||
|
"It's a number."
|
||
|
"It's a number."
|
||
|
"Lucky."</span></div><p>The first three macro calls (corresponding to the inner definition) invoked <tt>call-next-macro</tt>, while the last one didn't.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen">macrolet+ <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">foo <span class="paren4">(<span class="nonparen">x</span>)</span> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_numberp.html" class="symbol">numberp</a> x</span>)</span> <span class="string">"It's a number."</span> <span class="paren5">(<span class="nonparen">call-next-macro</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren2">(<span class="nonparen">macrolet+ <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">foo <span class="paren5">(<span class="nonparen">x</span>)</span> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_eql.html" class="symbol">eql</a> x 7</span>)</span> <span class="string">"Lucky."</span> <span class="paren6">(<span class="nonparen">call-next-macro</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_values.html" class="symbol">values</a> <span class="paren4">(<span class="nonparen">foo 12</span>)</span> <span class="paren4">(<span class="nonparen">foo 13</span>)</span> <span class="paren4">(<span class="nonparen">foo 1234567890</span>)</span> <span class="paren4">(<span class="nonparen">foo 'not-a-number</span>)</span></span>)</span></span>)</span></span>)</span></span></div><p>This signals an error:<p><pre>> Error: No macro definition for FOO.
|
||
|
> While executing: GET-MACRO, in process listener(1).
|
||
|
> Type :POP to abort, :R for a list of available restarts.
|
||
|
> Type :? for other options.</pre><p>In other words, there isn't any global definition of the <tt>foo</tt> macro. Availability can be checked with <tt>next-macro-p</tt>.<p><h2>Related reading</h2><p><ul>
|
||
|
<li>
|
||
|
<a href="https://groups.google.com/g/comp.lang.lisp/c/YGbZDFY9fdA/m/xMahTOhonnYJ">MACROLET and lexical environment</a>
|
||
|
</li>
|
||
|
<li>
|
||
|
<a href="https://www.cliki.net/site/HyperSpec/Body/sec_3-1-1-4.html">CLHS: Section 3.1.1.4—Environment Objects</a>
|
||
|
</li>
|
||
|
<li>
|
||
|
<a href="https://www.cliki.net/site/HyperSpec/Issues/iss229.html">Issue MACRO-ENVIRONMENT-EXTENT:DYNAMIC</a>
|
||
|
</li>
|
||
|
</ul>
|
||
|
<hr>
|
||
|
<a href="Apache 2.html" class="category">Apache 2</a></div></div>
|
||
|
<div id="footer" class="buttonbar"><ul><li><a href="call-next-macro.html">Current version</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/history?article=call-next-macro">History</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/backlinks?article=call-next-macro">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=call-next-macro&from-revision=3836685175">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
|
||
|
</div>
|
||
|
<div id="header-buttons" class="buttonbar">
|
||
|
<ul>
|
||
|
<li><a href="https://www.cliki.net/">Home</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
|
||
|
<li><a href="CLiki.html">About</a></li>
|
||
|
<li><a href="Text Formatting.html">Text Formatting</a></li>
|
||
|
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
|
||
|
</ul>
|
||
|
<div id="search">
|
||
|
<form action="https://www.cliki.net/site/search">
|
||
|
<label for="search_query" class="hidden">Search CLiki</label>
|
||
|
<input type="text" name="query" id="search_query" value="" />
|
||
|
<input type="submit" value="search" />
|
||
|
</form>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div id="pageheader">
|
||
|
<div id="header">
|
||
|
<span id="logo">CLiki</span>
|
||
|
<span id="slogan">the common lisp wiki</span>
|
||
|
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
|
||
|
<label for="login_name" class="hidden">Account name</label>
|
||
|
<input type="text" name="name" id="login_name" class="login_input" />
|
||
|
<label for= "login_password" class="hidden">Password</label>
|
||
|
<input type="password" name="password" id="login_password" class="login_input" />
|
||
|
<input type="submit" name="login" value="login" id="login_submit" /><br />
|
||
|
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
|
||
|
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
|
||
|
</form>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</body></html>
|