From 8a45c6a222d6d4fd48dbf3a3103a21372e91b77a Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Thu, 16 Nov 2023 14:33:42 -0500 Subject: [PATCH] Complicate the example reader macro `matrix` The previous version could be implemented as a regular macro. --- docs/macros.rst | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/macros.rst b/docs/macros.rst index 693bc7e98..c4ad7e40f 100644 --- a/docs/macros.rst +++ b/docs/macros.rst @@ -156,22 +156,32 @@ Ultimately it's wisest to use only four kinds of names in macro expansions: gens Reader macros ------------- -Reader macros allow you to hook directly into Hy's parser to customize how text is parsed into models. They're defined with :hy:func:`defreader`, or, like regular macros, brought in from other modules with :hy:func:`require`. Rather than receiving function arguments, a reader macro has access to a :py:class:`HyReader ` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`HyReader ` and its base class :py:class:`Reader ` for the available methods). A reader macro is called with the hash sign ``#``, and like a regular macro, it should return a model or something convertible to a model. :: +Reader macros allow you to hook directly into Hy's parser to customize how text is parsed into models. They're defined with :hy:func:`defreader`, or, like regular macros, brought in from other modules with :hy:func:`require`. Rather than receiving function arguments, a reader macro has access to a :py:class:`HyReader ` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`HyReader ` and its base class :py:class:`Reader ` for the available methods). A reader macro is called with the hash sign ``#``, and like a regular macro, it should return a model or something convertible to a model. + +Here's a moderately complex example of a reader macro that couldn't be implemented as a regular macro. It reads in a list of lists in which the inner lists are newline-separated, but newlines are allowed inside elements. :: (defreader matrix (.slurp-space &reader) (setv start (.getc &reader)) (assert (= start "[")) + (.slurp-space &reader) (setv out [[]]) - (while (not (do (.slurp-space &reader) (.peek-and-getc &reader "]"))) - (setv x (.parse-one-form &reader)) - (if (= x '|) - (.append out []) - (.append (get out -1) x))) - (if (= out [[]]) [] out)) - - (print (hy.repr #matrix [1 2 3 | 4 5 6 | 7 8 9])) - ; => [[1 2 3] [4 5 6] [7 8 9]] + (while (not (.peek-and-getc &reader "]")) + (cond + (any (gfor c " \t" (.peek-and-getc &reader c))) + None + (.peek-and-getc &reader "\n") + (.append out []) + True + (.append (get out -1) (.parse-one-form &reader)))) + (lfor line out :if line line)) + + (print (hy.repr #matrix [ + 1 (+ 1 1) 3 + 4 ["element" "containing" + "a" "newline"] 6 + 7 8 9])) + ; => [[1 2 3] [4 ["element" "containing" "a" "newline"] 6] [7 8 9]] Note that because reader macros are evaluated at parse-time, and top-level forms are completely parsed before any further compile-time execution occurs, you can't use a reader macro in the same top-level form that defines it::