-\section{Library {\tt H}: hygienic macros}\r
-\r
-\paragraph{Warning} This hygienic macro system is quite new and\r
-experimental. Its API is likely to evolve over the next versions of\r
-metalua. Feedbacks are especially welcome.\r
-\r
-A common problem with meta-programming tools is variable capture, and\r
-the art of automatically avoiding capture is called hygiene. the {\tt\r
- H} library automates as much as possible the handling of hygiene.\r
-\r
-The design of H tries to respect metalua's core principles:\r
-\begin{itemize}\r
-\item Nothing taboo under the hood: the underlying mechanisms of the\r
- language must remain simple enough to be intelligible to their\r
- intended users. Black magic should be banned from the desing. This\r
- rules out hygienic macros as a primitive: these either rely on very\r
- advanced and hard to predict mechanisms, or severely limit the\r
- manipulation tools available to the macro authors.\r
-\item Simple by default: advanced users should know what happens under\r
- the hood, but more casual users should be able to simply turn the\r
- ignition and drive. It should be possible to use H, for regular\r
- macros, without much understanding of its advanced principles and\r
- implementation.\r
-\item Everything's a regular program: again, most macro systems\r
- offering hygiene limit macro manipulations to a term rewriting\r
- framework, which might be Turing complete, but makes many advanced\r
- stuff cumbersome to write. AST are regular data, which must be\r
- manipulable by regular programs.\r
-\item Extension: metalua tries to offer the most extensible possible\r
- language to its users. If the author of the language couldn't\r
- implement a feature as a regular extension, it would probably\r
- outline a severe limitation of the system.\r
-\end{itemize}\r
-\r
-\paragraph{Inside captures}\r
-There are two kind of captures, inside a macro and outside a\r
-macro. People often think about inside captures, in parts because the\r
-C preprocessor is subject to it. It happens when a macro inserts user\r
-code in a quote, and the quote declares a local variable that shadows\r
-a user one:\r
-\r
-\begin{verbatim}\r
--{ block:\r
- require 'dollar'\r
- function dollar.TRICOND(cond, iftrue, iffalse)\r
- local code = +{ block:\r
- local tmp, result\r
- tmp = -{cond}\r
- if tmp then result = -{iftrue} \r
- else result = -{iffalse} end }\r
- return `Stat{ code, +{result} }\r
- end }\r
-\r
-local tmp = 5\r
-local foo = $TRICOND(tmp%2==0, "even", "odd")\r
-\end{verbatim}\r
-\r
-Here, the \verb|tmp| local variable used in the macro code captures\r
-the user's one, and cause a failure (an attempt to get the modulus of\r
-\verb|nil|). The expanded code looks like:\r
-\begin{Verbatim}\r
-local tmp = 5\r
-local foo = -{ `Stat{ +{ block:\r
- local tmp, result\r
- tmp = tmp%2==0\r
- if tmp then result = "even"\r
- else result = "odd" end\r
-}, +{result} } }\r
-\end{Verbatim}\r
-\r
-This is fixed by renaming automatically all local variables in the\r
-macro with fresh names. H provides an AST walker which does\r
-that. However, it needs to rename only macro code, not user-provided\r
-code; therefore the macro writer has to somehow mark the user\r
-code. This is done with the ``!'' prefix operator: sub-trees marked\r
-with ``!'' won't experience any renaming. The following version is\r
-therefore safe w.r.t. inside variable capture:\r
-\r
-\begin{verbatim}\r
--{ block:\r
- require 'dollar'\r
- function dollar.TRICOND(cond, iftrue, iffalse)\r
- local code = +{ block:\r
- local tmp, result\r
- tmp = -{!cond}\r
- if tmp then result = -{!iftrue} \r
- else result = -{!iffalse} end }\r
- return H(`Stat{ code, +{result} })\r
- end }\r
-\r
-local tmp = 5\r
-local foo = $TRICOND(tmp%2==0, "even", "odd")\r
-\end{verbatim}\r
-\r
-It expands to:\r
-\r
-\begin{Verbatim}\r
-local tmp = 5\r
-local foo = -{ `Stat{ +{ block:\r
- local -{`Id '.1.L.tmp'}, -{`Id '.2.L.result'} -- new fresh names\r
- -{`Id '.1.L.tmp'} = tmp%2==0 -- no capture!\r
- if -{`Id '.1.L.tmp'} then -{`Id '.2.L.result'} = "even"\r
- else -{`Id '.2.L.result'} = "odd" end\r
-}, `Id '.2.L.result' } }\r
-\end{Verbatim}\r
-\r
-\paragraph{Outside captures}\r
-We've seen that macros can capture the user's variables; but the\r
-opposite can also happen: the user can capture the variables required\r
-by a macro:\r
-\r
-\begin{Verbatim}\r
--{ block:\r
- require 'dollar'\r
- dollar.log = |x| +{ printf("%s = %s", \r
- -{table.tostring(x)}, \r
- table.tostring(-{x})) } }\r
-local x = { 1, 2, 3 }\r
-\$log(x) -- prints "`Id 'x' = { 1, 2, 3 }"\r
-\end{Verbatim}\r
-\r
-This expands to:\r
-\begin{Verbatim}\r
-printf("%s = %s", "`Id 'x'", table.tostring(x))\r
-\end{Verbatim}\r
-\r
-Now, replace "x" with "table", and you get an outside capture: "local\r
-table = { 1, 2, 3 } shadows the table module from which the macro\r
-tries to get table.tostring().\r
-\r
-The most widespread language which supports non-hygienic macros,\r
-Common Lisp, deals with that issue by being a Lisp-2: it has separate\r
-namespaces for functions and ``normal'' variables. This happens to\r
-remove many common capture cases. \r
-\r
-H fixes this by renaming the free variables in hygienized\r
-macros. After this, a "local new\_names = old\_names" statement is\r
-generated, which re-establishes the correspondance between\r
-names. Let's make the examples above hygienic:\r
-\r
-\begin{Verbatim}\r
--{ block:\r
- require 'dollar'\r
- dollar.log = |x| H+{ printf("%s = %s", \r
- -{!table.tostring(x)}, \r
- table.tostring(-{!x})) } }\r
-local table = { 1, 2, 3 }\r
-\$log(table) -- prints "`Id 'table' = { 1, 2, 3 }"\r
-\end{Verbatim}\r
-\r
-The code above expands into:\r
-\r
-\begin{Verbatim}\r
-local table = { 1, 2, 3 }\r
-(-{`Id '.1.X.printf'}) ("%s = %s",\r
- "`Id 'table'",\r
- (-{`Id '.2.X.table'}.tostring(table)))\r
-\end{Verbatim}\r
-\r
-To make this work, we need to introduce, somewhere where no variable\r
-is captured, the following local statement:\r
-\begin{Verbatim}\r
-local -{`Id '.1.X.printf'}, -{`Id '.2.X.table'} = printf, table\r
-\end{Verbatim}\r
-\r
-The correct way would be to let the user decide where this statement\r
-should go.\r
-\r
+\section{Library {\tt H}: hygienic macros}
+
+\paragraph{Warning} This hygienic macro system is quite new and
+experimental. Its API is likely to evolve over the next versions of
+metalua. Feedbacks are especially welcome.
+
+A common problem with meta-programming tools is variable capture, and
+the art of automatically avoiding capture is called hygiene. the {\tt
+ H} library automates as much as possible the handling of hygiene.
+
+The design of H tries to respect metalua's core principles:
+\begin{itemize}
+\item Nothing taboo under the hood: the underlying mechanisms of the
+ language must remain simple enough to be intelligible to their
+ intended users. Black magic should be banned from the desing. This
+ rules out hygienic macros as a primitive: these either rely on very
+ advanced and hard to predict mechanisms, or severely limit the
+ manipulation tools available to the macro authors.
+\item Simple by default: advanced users should know what happens under
+ the hood, but more casual users should be able to simply turn the
+ ignition and drive. It should be possible to use H, for regular
+ macros, without much understanding of its advanced principles and
+ implementation.
+\item Everything's a regular program: again, most macro systems
+ offering hygiene limit macro manipulations to a term rewriting
+ framework, which might be Turing complete, but makes many advanced
+ stuff cumbersome to write. AST are regular data, which must be
+ manipulable by regular programs.
+\item Extension: metalua tries to offer the most extensible possible
+ language to its users. If the author of the language couldn't
+ implement a feature as a regular extension, it would probably
+ outline a severe limitation of the system.
+\end{itemize}
+
+\paragraph{Inside captures}
+There are two kind of captures, inside a macro and outside a
+macro. People often think about inside captures, in parts because the
+C preprocessor is subject to it. It happens when a macro inserts user
+code in a quote, and the quote declares a local variable that shadows
+a user one:
+
+\begin{verbatim}
+-{ block:
+ require 'dollar'
+ function dollar.TRICOND(cond, iftrue, iffalse)
+ local code = +{ block:
+ local tmp, result
+ tmp = -{cond}
+ if tmp then result = -{iftrue}
+ else result = -{iffalse} end }
+ return `Stat{ code, +{result} }
+ end }
+
+local tmp = 5
+local foo = $TRICOND(tmp%2==0, "even", "odd")
+\end{verbatim}
+
+Here, the \verb|tmp| local variable used in the macro code captures
+the user's one, and cause a failure (an attempt to get the modulus of
+\verb|nil|). The expanded code looks like:
+\begin{Verbatim}
+local tmp = 5
+local foo = -{ `Stat{ +{ block:
+ local tmp, result
+ tmp = tmp%2==0
+ if tmp then result = "even"
+ else result = "odd" end
+}, +{result} } }
+\end{Verbatim}
+
+This is fixed by renaming automatically all local variables in the
+macro with fresh names. H provides an AST walker which does
+that. However, it needs to rename only macro code, not user-provided
+code; therefore the macro writer has to somehow mark the user
+code. This is done with the ``!'' prefix operator: sub-trees marked
+with ``!'' won't experience any renaming. The following version is
+therefore safe w.r.t. inside variable capture:
+
+\begin{verbatim}
+-{ block:
+ require 'dollar'
+ function dollar.TRICOND(cond, iftrue, iffalse)
+ local code = +{ block:
+ local tmp, result
+ tmp = -{!cond}
+ if tmp then result = -{!iftrue}
+ else result = -{!iffalse} end }
+ return H(`Stat{ code, +{result} })
+ end }
+
+local tmp = 5
+local foo = $TRICOND(tmp%2==0, "even", "odd")
+\end{verbatim}
+
+It expands to:
+
+\begin{Verbatim}
+local tmp = 5
+local foo = -{ `Stat{ +{ block:
+ local -{`Id '.1.L.tmp'}, -{`Id '.2.L.result'} -- new fresh names
+ -{`Id '.1.L.tmp'} = tmp%2==0 -- no capture!
+ if -{`Id '.1.L.tmp'} then -{`Id '.2.L.result'} = "even"
+ else -{`Id '.2.L.result'} = "odd" end
+}, `Id '.2.L.result' } }
+\end{Verbatim}
+
+\paragraph{Outside captures}
+We've seen that macros can capture the user's variables; but the
+opposite can also happen: the user can capture the variables required
+by a macro:
+
+\begin{Verbatim}
+-{ block:
+ require 'dollar'
+ dollar.log = |x| +{ printf("%s = %s",
+ -{table.tostring(x)},
+ table.tostring(-{x})) } }
+local x = { 1, 2, 3 }
+\$log(x) -- prints "`Id 'x' = { 1, 2, 3 }"
+\end{Verbatim}
+
+This expands to:
+\begin{Verbatim}
+printf("%s = %s", "`Id 'x'", table.tostring(x))
+\end{Verbatim}
+
+Now, replace "x" with "table", and you get an outside capture: "local
+table = { 1, 2, 3 } shadows the table module from which the macro
+tries to get table.tostring().
+
+The most widespread language which supports non-hygienic macros,
+Common Lisp, deals with that issue by being a Lisp-2: it has separate
+namespaces for functions and ``normal'' variables. This happens to
+remove many common capture cases.
+
+H fixes this by renaming the free variables in hygienized
+macros. After this, a "local new\_names = old\_names" statement is
+generated, which re-establishes the correspondance between
+names. Let's make the examples above hygienic:
+
+\begin{Verbatim}
+-{ block:
+ require 'dollar'
+ dollar.log = |x| H+{ printf("%s = %s",
+ -{!table.tostring(x)},
+ table.tostring(-{!x})) } }
+local table = { 1, 2, 3 }
+\$log(table) -- prints "`Id 'table' = { 1, 2, 3 }"
+\end{Verbatim}
+
+The code above expands into:
+
+\begin{Verbatim}
+local table = { 1, 2, 3 }
+(-{`Id '.1.X.printf'}) ("%s = %s",
+ "`Id 'table'",
+ (-{`Id '.2.X.table'}.tostring(table)))
+\end{Verbatim}
+
+To make this work, we need to introduce, somewhere where no variable
+is captured, the following local statement:
+\begin{Verbatim}
+local -{`Id '.1.X.printf'}, -{`Id '.2.X.table'} = printf, table
+\end{Verbatim}
+
+The correct way would be to let the user decide where this statement
+should go.
+