Skip to content

Commit 05bb450

Browse files
authored
Merge pull request #2575 from Kodiologist/docs-content-2
More content edits for the manual
2 parents 225017d + b827e06 commit 05bb450

12 files changed

+305
-464
lines changed

CONTRIBUTING.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ NEWS and AUTHORS
9292
----------------
9393

9494
If you're making user-visible changes to the code, add one or more
95-
items describing it to the NEWS file.
95+
items describing them to the NEWS file.
9696

9797
Finally, add yourself to the AUTHORS file (as a separate commit): you
9898
deserve it. :)

docs/api.rst

+121-223
Large diffs are not rendered by default.

docs/macros.rst

+17
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _macros:
2+
13
======
24
Macros
35
======
@@ -161,6 +163,21 @@ Reader macros
161163

162164
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 <hy.core.macros.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 <hy.reader.hy_reader.HyReader>` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`HyReader <hy.reader.hy_reader.HyReader>` and its base class :py:class:`Reader <hy.reader.reader.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.
163165

166+
The simplest kind of reader macro doesn't read anything::
167+
168+
(defreader hi
169+
`(print "Hello."))
170+
171+
#hi #hi #hi
172+
173+
A less trivial, and more common, usage of reader macros is to call :func:`HyReader.parse-one-form <hy.reader.hy_reader.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. ::
174+
175+
(defreader do-twice
176+
(setv x (.parse-one-form &reader))
177+
`(do ~x ~x))
178+
179+
#do-twice (print "This line prints twice.")
180+
164181
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. ::
165182

166183
(defreader matrix

docs/model_patterns.rst

+17-10
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ Suppose you want to validate and extract the components of a form like::
2727
(foo8))))
2828

2929
You could do this with loops and indexing, but it would take a lot of code and
30-
be error-prone. Model patterns concisely express the general form of an
31-
expression to be matched, like what a regular expression does for text. Here's
32-
a pattern for a ``try`` form of the above kind::
30+
be error-prone. Model patterns concisely express the general form of a model
31+
tree to be matched, like what a regular expression does for text. Here's a
32+
pattern for a ``try`` form of the above kind::
3333

3434
(import
3535
funcparserlib.parser [maybe many]
3636
hy.model-patterns *)
37+
3738
(setv parser (whole [
3839
(sym "try")
3940
(many (notpexpr "except" "else" "finally"))
@@ -78,15 +79,15 @@ built-in parsers:
7879
- ``(some function)`` takes a predicate ``function`` and matches a form if it
7980
satisfies the predicate.
8081

81-
The best reference for Hy's parsers is the docstrings (use ``(help
82-
hy.model-patterns)``), but again, here are some of the more important ones:
82+
Some of the more important of Hy's own parsers are:
8383

84-
- ``FORM`` matches anything.
85-
- ``SYM`` matches any symbol.
86-
- ``(sym "foo")`` or ``(sym ":foo")`` matches and discards (per ``skip``) the
84+
- :data:`FORM <hy.model_patterns.FORM>` matches anything.
85+
- :data:`SYM <hy.model_patterns.SYM>` matches any symbol.
86+
- :func:`sym <hy.model_patterns.sym>` matches and discards (per ``skip``) the
8787
named symbol or keyword.
88-
- ``(brackets ...)`` matches the arguments in square brackets.
89-
- ``(pexpr ...)`` matches the arguments in parentheses.
88+
- :func:`brackets <hy.model_patterns.brackets>` matches the arguments in square
89+
brackets.
90+
- :func:`pexpr <hy.model_patterns.pexpr>` matches the arguments in parentheses.
9091

9192
Here's how you could write a simple macro using model patterns::
9293

@@ -105,3 +106,9 @@ Here's how you could write a simple macro using model patterns::
105106
A failed parse will raise ``funcparserlib.parser.NoParseError``.
106107

107108
.. _funcparserlib: https://github.com/vlasovskikh/funcparserlib
109+
110+
Reference
111+
---------
112+
113+
.. automodule:: hy.model_patterns
114+
:members:

hy/core/macros.hy

+6-38
Original file line numberDiff line numberDiff line change
@@ -51,44 +51,12 @@
5151
`(if ~test (do ~@body) None))
5252

5353
(defmacro defreader [_hy_compiler key #* body]
54-
"Define a new reader macro.
55-
56-
Reader macros are expanded at read time and allow you to modify the behavior
57-
of the Hy reader. Access to the currently instantiated `HyReader` is available
58-
in the ``body`` as ``&reader``. See :py:class:`HyReader <hy.reader.hy_reader.HyReader>`
59-
and its base class :py:class:`Reader <hy.reader.reader.Reader>` for details
60-
regarding the available processing methods.
61-
62-
Reader macro names can be any valid identifier and are callable by prefixing
63-
the name with a ``#``. i.e. ``(defreader upper ...)`` is called with ``#upper``.
64-
65-
Examples:
66-
67-
The following is a primitive example of a reader macro that adds Python's
68-
colon ``:`` slice sugar into Hy::
69-
70-
=> (defreader slice
71-
... (defn parse-node []
72-
... (let [node (when (!= \":\" (.peekc &reader))
73-
... (.parse-one-form &reader))]
74-
... (if (= node '...) 'Ellipse node)))
75-
...
76-
... (with [(&reader.end-identifier \":\")]
77-
... (let [nodes []]
78-
... (&reader.slurp-space)
79-
... (nodes.append (parse-node))
80-
... (while (&reader.peek-and-getc \":\")
81-
... (nodes.append (parse-node)))
82-
...
83-
... `(slice ~@nodes))))
84-
85-
=> (setv an-index 42)
86-
=> #slice a:(+ 1 2):\"column\"
87-
(slice 42 3 column)
88-
89-
See the :ref:`reader macros docs <reader-macros>` for more detailed
90-
information on how reader macros work and are defined.
91-
"
54+
"Define a reader macro, at both compile-time and run-time. After the name,
55+
all arguments are body forms: there is no parameter list as for ``defmacro``,
56+
since it's up to the reader macro to decide how to parse the source text
57+
following its call position. See :ref:`reader-macros` for details and
58+
examples."
59+
9260
(when (not (isinstance _hy_compiler.scope hy.scoping.ScopeGlobal))
9361
(raise (_hy_compiler._syntax-error
9462
_hy_compiler.this

hy/core/result_macros.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ def compile_augassign_expression(compiler, expr, root, target, values):
461461

462462

463463
@pattern_macro("setv", [many(maybe_annotated(FORM) + FORM)])
464-
@pattern_macro(((3, 8), "setx"), [times(1, 1, SYM + FORM)])
464+
@pattern_macro("setx", [times(1, 1, SYM + FORM)])
465465
def compile_def_expression(compiler, expr, root, decls):
466466
if not decls:
467467
return asty.Constant(expr, value=None)

hy/core/util.hy

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@
3838
(setv _gensym_lock (Lock))
3939

4040
(defn gensym [[g ""]]
41-
#[[Generate a symbol with a unique name. The argument will be included in the
42-
generated symbol name, as an aid to debugging. Typically one calls ``hy.gensym``
43-
without an argument.
41+
42+
#[[Generate a symbol with a unique name. The argument, if provided,
43+
will be included in the generated symbol name, as an aid to
44+
debugging.
4445
4546
The below example uses the return value of ``f`` twice but calls it only
4647
once, and uses ``hy.gensym`` for the temporary variable to avoid collisions
47-
with any other variable names.
48-
49-
::
48+
with any other variable names. ::
5049
5150
(defmacro selfadd [x]
5251
(setv g (hy.gensym))
@@ -59,6 +58,7 @@
5958
4)
6059
6160
(print (selfadd (f)))]]
61+
6262
(.acquire _gensym_lock)
6363
(try
6464
(global _gensym_counter)

hy/model_patterns.py

+47-20
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,28 @@
3131
Tuple,
3232
)
3333

34+
35+
#: Match any token.
3436
FORM = some(lambda _: True).named('form')
37+
#: Match a :class:`Symbol <hy.models.Symbol>`.
3538
SYM = some(lambda x: isinstance(x, Symbol)).named('Symbol')
39+
#: Match a :class:`Keyword <hy.models.Keyword>`.
3640
KEYWORD = some(lambda x: isinstance(x, Keyword)).named('Keyword')
37-
STR = some(lambda x: isinstance(x, String)).named('String') # matches literal strings only!
41+
#: Match a :class:`String <hy.models.String>`.
42+
STR = some(lambda x: isinstance(x, String)).named('String')
43+
#: Match any model type denoting a literal.
3844
LITERAL = some(lambda x: isinstance(x, (String, Integer, Float, Complex, Bytes))).named('literal')
3945

4046

4147
def sym(wanted):
42-
"Parse and skip the given symbol or keyword."
48+
"""Match and skip a symbol with a name equal to the string ``wanted``.
49+
You can begin the string with ``":"`` to check for a keyword instead."""
4350
return _sym(wanted, skip)
4451

4552

4653
def keepsym(wanted):
47-
"Parse the given symbol or keyword."
54+
"""As :func:`sym`, but the object is kept instead of
55+
skipped."""
4856
return _sym(wanted)
4957

5058

@@ -56,7 +64,7 @@ def _sym(wanted, f=lambda x: x):
5664

5765

5866
def whole(parsers):
59-
"""Parse the parsers in the given list one after another, then
67+
"""Match the parsers in the given list one after another, then
6068
expect the end of the input."""
6169
if len(parsers) == 0:
6270
return finished >> (lambda x: [])
@@ -72,34 +80,43 @@ def _grouped(group_type, syntax_example, name, parsers):
7280
(lambda x: group_type(whole(parsers).parse(x)).replace(x, recursive=False))
7381
)
7482
def brackets(*parsers, name = None):
75-
"Parse the given parsers inside square brackets."
83+
"""Match the given parsers inside square brackets (a :class:`List
84+
<hy.models.List>`)."""
7685
return _grouped(List, '[ … ]', name, parsers)
7786
def in_tuple(*parsers, name = None):
87+
"Match the given parsers inside a :class:`Tuple <hy.models.Tuple>`."
7888
return _grouped(Tuple, '#( … )', name, parsers)
7989
def braces(*parsers, name = None):
80-
"Parse the given parsers inside curly braces"
90+
"""Match the given parsers inside curly braces (a :class:`Dict
91+
<hy.models.Dict>`)."""
8192
return _grouped(Dict, '{ … }', name, parsers)
8293
def pexpr(*parsers, name = None):
83-
"Parse the given parsers inside a parenthesized expression."
94+
"""Match the given parsers inside a parenthesized :class:`Expression
95+
<hy.models.Expression>`."""
8496
return _grouped(Expression, '( … )', name, parsers)
8597

8698

8799
def dolike(head):
88-
"Parse a `do`-like form."
100+
"""Parse a :hy:func:`do`-like expression. ``head`` is a string used to
101+
construct a symbol for the head."""
89102
return pexpr(sym(head), many(FORM))
90103

91104

92105
def notpexpr(*disallowed_heads):
93-
"""Parse any object other than a hy.models.Expression beginning with a
94-
hy.models.Symbol equal to one of the disallowed_heads."""
106+
"""Parse any object other than an expression headed by a symbol whose name
107+
is equal to one of the given strings."""
95108
disallowed_heads = list(map(Symbol, disallowed_heads))
96109
return some(
97110
lambda x: not (isinstance(x, Expression) and x and x[0] in disallowed_heads)
98111
)
99112

100113

101114
def unpack(kind, content_type = None):
102-
"Parse an unpacking form, returning it unchanged."
115+
"""Parse an unpacking form, returning it unchanged. ``kind`` should be
116+
``"iterable"``, ``"mapping"``, or ``"either"``. If ``content_type`` is
117+
provided, the parser also checks that the unpacking form has exactly one
118+
argument and that argument inherits from ``content_type``."""
119+
103120
return some(lambda x:
104121
isinstance(x, Expression) and
105122
len(x) > 0 and
@@ -110,8 +127,9 @@ def unpack(kind, content_type = None):
110127

111128

112129
def times(lo, hi, parser):
113-
"""Parse `parser` several times (`lo` to `hi`) in a row. `hi` can be
114-
float('inf'). The result is a list no matter the number of instances."""
130+
"""Parse ``parser`` several times (from ``lo`` to ``hi``, inclusive) in a
131+
row. ``hi`` can be ``float('inf')``. The result is a list no matter the
132+
number of instances."""
115133

116134
@Parser
117135
def f(tokens, s):
@@ -132,24 +150,33 @@ def f(tokens, s):
132150

133151

134152
Tag = namedtuple("Tag", ["tag", "value"])
153+
Tag.__doc__ = 'A named tuple; see :func:`collections.namedtuple` and :func:`tag`.'
135154

136155

137156
def tag(tag_name, parser):
138-
"""Matches the given parser and produces a named tuple `(Tag tag value)`
139-
with `tag` set to the given tag name and `value` set to the parser's
140-
value."""
157+
"""Match on ``parser`` and produce an instance of :class:`Tag`
158+
with ``tag`` set to ``tag_name`` and ``value`` set to result of matching
159+
``parser``."""
141160
return parser >> (lambda x: Tag(tag_name, x))
142161

143162

144163
def parse_if(pred, parser):
145-
"""
146-
Return a parser that parses a token with `parser` if it satisfies the
147-
predicate `pred`.
148-
"""
164+
"""Return a parser that parses a token with ``parser`` if it satisfies the
165+
predicate ``pred``."""
149166

150167
@Parser
151168
def _parse_if(tokens, s):
152169
some(pred).run(tokens, s)
153170
return parser.run(tokens, s)
154171

155172
return _parse_if
173+
174+
175+
__all__ = [
176+
'FORM', 'SYM', 'KEYWORD', 'STR', 'LITERAL',
177+
'sym', 'keepsym',
178+
'whole',
179+
'brackets', 'in_tuple', 'braces', 'pexpr',
180+
'dolike', 'notpexpr',
181+
'unpack', 'times',
182+
'Tag', 'tag', 'parse_if']

hy/models.py

+9-28
Original file line numberDiff line numberDiff line change
@@ -104,36 +104,17 @@ def __hash__(self):
104104

105105

106106
def as_model(x):
107-
"""Recursively promote an object ``x`` into its canonical model form.
107+
"""Convert ``x`` and any elements thereof into :ref:`models <models>`
108+
recursively. This function is called implicitly by Hy in many situations,
109+
such as when inserting the expansion of a macro into the surrounding code,
110+
so you don't often need to call it. One use is to ensure that models are
111+
used on both sides of a comparison::
108112
109-
When creating macros its possible to return non-Hy model objects or
110-
even create an expression with non-Hy model elements::
113+
(= 7 '7) ; => False
114+
(= (hy.as-model 7) '7) ; => True
111115
112-
=> (defmacro hello []
113-
... "world!")
114-
115-
=> (defmacro print-inc [a]
116-
... `(print ~(+ a 1)))
117-
=> (print-inc 1)
118-
2 ; in this case the unquote form (+ 1 1) would splice the literal
119-
; integer ``2`` into the print statement, *not* the model representation
120-
; ``(hy.model.Integer 2)``
121-
122-
This is perfectly fine, because Hy autoboxes these literal values into their
123-
respective model forms at compilation time.
124-
125-
The one case where this distinction between the spliced composit form and
126-
the canonical model tree representation matters, is when comparing some
127-
spliced model tree with another known tree::
128-
129-
=> (= `(print ~(+ 1 1)) '(print 2))
130-
False ; False because the literal int ``2`` in the spliced form is not
131-
; equal to the ``(hy.model.Integer 2)`` value in the known form.
132-
133-
=> (= (hy.as-model `(print ~(+ 1 1)) '(print 2)))
134-
True ; True because ``as-model`` has walked the expression and promoted
135-
; the literal int ``2`` to its model for ``(hy.model.Integer 2)``
136-
"""
116+
It's an error to call ``hy.as-model`` on an object that contains itself, or
117+
an object that isn't representable as a Hy literal, such as a function."""
137118

138119
if id(x) in _seen:
139120
raise HyWrapperError("Self-referential structure detected in {!r}".format(x))

0 commit comments

Comments
 (0)