Skip to content

Commit

Permalink
Merge pull request #2569 from Kodiologist/docs-org
Browse files Browse the repository at this point in the history
Reorganization and additions for the manual
  • Loading branch information
Kodiologist authored Apr 24, 2024
2 parents cfb52e5 + bdc7974 commit 3d70cb4
Show file tree
Hide file tree
Showing 10 changed files with 1,098 additions and 1,000 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Contributor Guidelines
Contributor guidelines
======================

Contributions are welcome and greatly appreciated. Every little bit
Expand Down
1,925 changes: 989 additions & 936 deletions docs/api.rst

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/cli.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
======================
Command-Line Interface
Command-line interface
======================

Hy provides a handful of command-line programs for working with Hy code.
Expand Down
2 changes: 1 addition & 1 deletion docs/env_var.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
=====================
Environment Variables
Environment variables
=====================

Hy treats the following environment variables specially. Boolean environment
Expand Down
2 changes: 1 addition & 1 deletion docs/hacking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

.. include:: ../CONTRIBUTING.rst

Core Team
Core team
=========

Hy's core development team consists of the following people:
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ Linux, Windows, and Mac OS), and on recent versions of PyPy and Pyodide.
syntax
semantics
macros
model_patterns
repl
env_var
cli
interop
model_patterns
api
hacking
58 changes: 41 additions & 17 deletions docs/interop.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
.. _interop:

=======================
Python Interoperability
Python interoperability
=======================

.. contents:: Contents
:local:

Mangling
========

:ref:`Mangling <mangling>` allows variable names to be spelled differently in
Hy and Python. For example, Python's ``str.format_map`` can be written
``str.format-map`` in Hy, and a Hy function named ``valid?`` would be called
``hyx_valid_Xquestion_markX`` in Python. You can call :hy:func:`hy.mangle` and
:hy:func:`hy.unmangle` from either language.

.. contents:: Contents
:local:
Libraries that expect Python
============================

There are various means by which Hy may interact poorly with a Python library because the library doesn't account for the possibility of Hy. For example,
when you run :ref:`hy-cli`, ``sys.executable`` will be set to
this program rather than the original Python binary. This is helpful more often
than not, but will lead to trouble if e.g. the library tries to call
:py:data:`sys.executable` with the ``-c`` option. In this case, you can try
setting :py:data:`sys.executable` back to ``hy.sys-executable``, which is a
saved copy of the original value. More generally, you can use :ref:`hy2py`, or you
can put a simple Python wrapper script like ``import hy, my_hy_program`` in
front of your code.

See `the wiki
<https://github.com/hylang/hy/wiki/Compatibility-tips>`_ for tips
on using specific packages.

Packaging a Hy library
======================

Generally, the same infrastructure used for Python packages, such as
``setup.py`` files and the `Python Package Index (PyPI) <https://pypi.org/>`__,
is applicable to Hy. Don't write the setup file itself in Hy, since you'll be
declaring your package's dependence on Hy there, likely in the
``install_requires`` argument of ``setup``. See :ref:`using-hy-from-python`
below for some related issues to keep in mind.

If you want to compile your Hy code into Python bytecode at installation-time
(in case e.g. the code is being installed to a directory where the bytecode be
able to be automatically written later, due to permissions issues), see Hy's
own ``setup.py`` for an example.

Using Python from Hy
====================
Expand All @@ -24,6 +59,8 @@ You can embed Python code directly into a Hy program with the macros
tools like :func:`eval` or :func:`exec` to execute or manipulate Python code in
strings.

.. _using-hy-from-python:

Using Hy from Python
====================

Expand Down Expand Up @@ -54,17 +91,4 @@ There is no Hy equivalent of :func:`exec` because :hy:func:`hy.eval` works
even when the input isn't equivalent to a single Python expression.

You can use :meth:`hy.REPL.run` to launch the Hy REPL from Python, as in
``hy.REPL(locals = locals()).run()``.

Libraries that expect Python
============================

There are various means by which Hy may interact poorly with a Python library because the library doesn't account for the possibility of Hy. For example,
when you run :ref:`hy-cli`, ``sys.executable`` will be set to
this program rather than the original Python binary. This is helpful more often
than not, but will lead to trouble if e.g. the library tries to call
:py:data:`sys.executable` with the ``-c`` option. In this case, you can try
setting :py:data:`sys.executable` back to ``hy.sys-executable``, which is a
saved copy of the original value. More generally, you can use :ref:`hy2py`, or you
can put a simple Python wrapper script like ``import hy, my_hy_program`` in
front of your code.
``hy.REPL(locals = {**globals(), **locals()}).run()``.
2 changes: 1 addition & 1 deletion docs/model_patterns.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
==============
Model Patterns
Model patterns
==============

The module ``hy.model-patterns`` provides a library of parser combinators for
Expand Down
39 changes: 30 additions & 9 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ like so::
``require`` can pull in a reader macro defined in a different module with
syntax like ``(require mymodule :readers [d])``.

Hyrule
======
Recommended libraries
=====================

`Hyrule <https://pypi.org/project/hyrule>`_ is Hy's standard utility library.
It provides a variety of functions and macros that are useful for writing Hy
Expand All @@ -364,11 +364,31 @@ programs. ::
=> (import hyrule [inc])
=> (list (map inc [1 2 3]))
[2 3 4]
=> (require hyrule [assoc])
=> (setv d {})
=> (assoc d "a" 1 "b" 2)
=> d
{"a" 1 "b" 2}
=> (require hyrule [case])
=> (setv x 2)
=> (case x 1 "a" 2 "b" 3 "c")
"b"

`toolz <https://pypi.org/project/toolz/>`_ and its Cython variant `cytoolz
<https://pypi.org/project/cytoolz/>`_ provide lots of utilities for functional
programming and working with iterables. ::

=> (import toolz [partition])
=> (list (partition 2 [1 2 3 4 5 6]))
[#(1 2) #(3 4) #(5 6)]

`metadict <https://pypi.org/project/metadict/>`_ allows you to refer to the
elements of a dictionary as attributes. This is handy when frequently referring
to elements with constant strings as keys, since plain indexing is a bit
verbose in Hy. ::

=> (import metadict [MetaDict])
=> (setv d (MetaDict))
=> (setv d.foo 1) ; i.e., (setv (get d "foo") 1)
=> d.foo ; i.e., (get d "foo")
1
=> (list (.keys d))
["foo"]

Next steps
==========
Expand All @@ -384,8 +404,9 @@ understand example code for Python libraries.

Refer to the rest of this manual for Hy-specific features. Like Hy itself, the
manual is incomplete, but :ref:`contributions <hacking>` are always welcome.
For an official full-blown example Hy program, see `Infinitesimal Quest 2 + ε
<http://hylang.org/simalq>`_.
See `the wiki <https://github.com/hylang/hy/wiki/Compatibility-tips>`_ for tips
on getting Hy to work with other software. For an official full-blown example
Hy program, see `Infinitesimal Quest 2 + ε <http://hylang.org/simalq>`_.

Bear in mind that Hy is still unstable, and with each release along the
way to Hy 1.0, there are new breaking changes. Refer to `the NEWS file
Expand Down
64 changes: 32 additions & 32 deletions hy/core/result_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,17 @@ def compile_inline_python(compiler, expr, root, code):
return Result(stmts=o) if exec_mode else o


@pattern_macro("pragma", [many(KEYWORD + FORM)])
def compile_pragma(compiler, expr, root, kwargs):
for kw, value in kwargs:
if kw == Keyword("warn-on-core-shadow"):
compiler.local_state_stack[-1]['warn_on_core_shadow'] = (
bool(compiler.eval(value)))
else:
raise compiler._syntax_error(kw, f"Unknown pragma `{kw}`. Perhaps it's implemented by a newer version of Hy.")
return Result()


# ------------------------------------------------
# * Quoting
# ------------------------------------------------
Expand Down Expand Up @@ -470,6 +481,19 @@ def compile_def_expression(compiler, expr, root, decls):
return result


@pattern_macro("let", [brackets(many(maybe_annotated(FORM) + FORM)), many(FORM)])
def compile_let(compiler, expr, root, bindings, body):
res = Result()
bindings = bindings[0]
scope = compiler.scope.create(ScopeLet)

for (target, ann), value in bindings:
res += compile_assign(compiler, ann, target, value, let_scope=scope)

with scope:
return res + compiler.compile(mkexpr("do", *body).replace(expr))


@pattern_macro(["annotate"], [FORM, FORM])
def compile_basic_annotation(compiler, expr, root, target, ann):
return compile_assign(compiler, ann, target, None)
Expand Down Expand Up @@ -526,6 +550,14 @@ def compile_assign(
return result


@pattern_macro(((3, 12), "deftype"), [maybe(type_params), SYM, FORM])
def compile_deftype(compiler, expr, root, tp, name, value):
return asty.TypeAlias(expr,
name = asty.Name(name, id = mangle(name), ctx = ast.Store()),
value = compiler.compile(value).force_expr,
**digest_type_params(compiler, tp))


@pattern_macro(["global", "nonlocal"], [many(SYM)])
def compile_global_or_nonlocal(compiler, expr, root, syms):
if not syms:
Expand Down Expand Up @@ -2003,38 +2035,6 @@ def compile_assert_expression(compiler, expr, root, test, msg):
)


@pattern_macro("let", [brackets(many(maybe_annotated(FORM) + FORM)), many(FORM)])
def compile_let(compiler, expr, root, bindings, body):
res = Result()
bindings = bindings[0]
scope = compiler.scope.create(ScopeLet)

for (target, ann), value in bindings:
res += compile_assign(compiler, ann, target, value, let_scope=scope)

with scope:
return res + compiler.compile(mkexpr("do", *body).replace(expr))


@pattern_macro(((3, 12), "deftype"), [maybe(type_params), SYM, FORM])
def compile_deftype(compiler, expr, root, tp, name, value):
return asty.TypeAlias(expr,
name = asty.Name(name, id = mangle(name), ctx = ast.Store()),
value = compiler.compile(value).force_expr,
**digest_type_params(compiler, tp))


@pattern_macro("pragma", [many(KEYWORD + FORM)])
def compile_pragma(compiler, expr, root, kwargs):
for kw, value in kwargs:
if kw == Keyword("warn-on-core-shadow"):
compiler.local_state_stack[-1]['warn_on_core_shadow'] = (
bool(compiler.eval(value)))
else:
raise compiler._syntax_error(kw, f"Unknown pragma `{kw}`. Perhaps it's implemented by a newer version of Hy.")
return Result()


@pattern_macro(
"unquote unquote-splice unpack-mapping except except* finally else".split(),
[many(FORM)],
Expand Down

0 comments on commit 3d70cb4

Please sign in to comment.