From f539436baf2c31faa99fea2081efe8cb2ee69603 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Tue, 30 Apr 2024 11:11:59 -0400 Subject: [PATCH] Make user-facing reader stuff direct kids of `hy` because having to say `hy.reader.reader.Reader` is ridiculous. --- docs/api.rst | 6 +++--- docs/macros.rst | 4 ++-- hy/__init__.py | 3 +++ hy/reader/__init__.py | 8 +++++--- hy/reader/hy_reader.py | 2 +- hy/reader/reader.py | 4 ++-- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 8fd250a5c..a30430a28 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1307,13 +1307,13 @@ Readers Hy's reader (i.e., parser) classes are most interesting to the user in the context of :ref:`reader macros `. -.. autoclass:: hy.reader.hy_reader.HyReader +.. autoclass:: hy.HyReader :members: parse, parse_one_form, parse_forms_until, read_default, fill_pos -.. autoclass:: hy.reader.reader.Reader +.. autoclass:: hy.Reader :members: -.. autoexception:: hy.reader.exceptions.PrematureEndOfInput +.. autoexception:: hy.PrematureEndOfInput .. _pyop: diff --git a/docs/macros.rst b/docs/macros.rst index 8199916a6..bceb4be08 100644 --- a/docs/macros.rst +++ b/docs/macros.rst @@ -161,7 +161,7 @@ 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:`hy.HyReader` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`hy.HyReader` and its base class :py:class:`hy.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. The simplest kind of reader macro doesn't read anything:: @@ -170,7 +170,7 @@ The simplest kind of reader macro doesn't read anything:: #hi #hi #hi -A less trivial, and more common, usage of reader macros is to call :func:`HyReader.parse-one-form ` to get a single form from the following source text. Such a reader macro is like a unary regular macro that's called with ``#`` instead of parentheses. :: +A less trivial, and more common, usage of reader macros is to call :func:`hy.HyReader.parse_one_form` to get a single form from the following source text. Such a reader macro is like a unary regular macro that's called with ``#`` instead of parentheses. :: (defreader do-twice (setv x (.parse-one-form &reader)) diff --git a/hy/__init__.py b/hy/__init__.py index afa43dcd4..d7510c108 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -46,6 +46,9 @@ def __getattr__(self, s): disassemble="hy.core.util", as_model="hy.models", REPL="hy.repl", + Reader="hy.reader.reader", + HyReader="hy.reader.hy_reader", + PrematureEndOfInput="hy.reader.exceptions" ) diff --git a/hy/reader/__init__.py b/hy/reader/__init__.py index 09147c8c4..3b8af868d 100644 --- a/hy/reader/__init__.py +++ b/hy/reader/__init__.py @@ -12,8 +12,8 @@ def read_many(stream, filename="", reader=None, skip_shebang=False): """Parse all the Hy source code in ``stream``, which should be a textual file-like object or a string. ``filename``, if provided, is used in error messages. If no - ``reader`` is provided, a new :class:`hy.reader.hy_reader.HyReader` object is created. - If ``skip_shebang`` is true and a :ref:`shebang line ` is present, it's + ``reader`` is provided, a new :class:`hy.HyReader` object is created. If + ``skip_shebang`` is true and a :ref:`shebang line ` is present, it's detected and discarded first. Return a value of type :class:`hy.models.Lazy`. If you want to evaluate this, be @@ -25,7 +25,9 @@ def read_many(stream, filename="", reader=None, skip_shebang=False): .. warning:: Thanks to reader macros, reading can execute arbitrary code. Don't read untrusted - input.""" + input. + + """ if isinstance(stream, str): stream = StringIO(stream) diff --git a/hy/reader/hy_reader.py b/hy/reader/hy_reader.py index f35824357..451052e62 100644 --- a/hy/reader/hy_reader.py +++ b/hy/reader/hy_reader.py @@ -112,7 +112,7 @@ def err(msg): class HyReader(Reader): """A modular reader for Hy source. It inherits from - :py:class:`hy.reader.reader.Reader`. + :py:class:`hy.Reader`. When ``use_current_readers`` is true, initialize this reader with all reader macros from the calling module.""" diff --git a/hy/reader/reader.py b/hy/reader/reader.py index 40f678c65..21cd0b954 100644 --- a/hy/reader/reader.py +++ b/hy/reader/reader.py @@ -46,7 +46,7 @@ def __new__(cls, name, bases, namespace): class Reader(metaclass=ReaderMeta): """An abstract base class for reading input character-by-character. - See :py:class:`HyReader ` for an example + See :py:class:`hy.HyReader` for an example of creating a reader class. Attributes: @@ -176,7 +176,7 @@ def peek_and_getc(self, target): def chars(self, eof_ok=False): """Consume and yield characters of the stream. If ``eof_ok`` is false (the default) and the end of the stream is reached, - raise :exc:`hy.reader.exceptions.PrematureEndOfInput`.""" + raise :exc:`hy.PrematureEndOfInput`.""" while True: c = self.getc()