]> git.lizzy.rs Git - metalua.git/blobdiff - doc/manual/hygiene-ref.tex
fix CRLF
[metalua.git] / doc / manual / hygiene-ref.tex
index 9def0f8bf0d4fde2f011e9b3b8558fc7bf088b79..3fa3d73edd71f01b5a8875dfa2697638b1d3dcbb 100644 (file)
-\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.
+