summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst16
-rw-r--r--_templates/globaltoc.html11
-rw-r--r--_templates/localtoc.html13
-rwxr-xr-xconf.py8
-rw-r--r--docs/embedding.rst9
-rw-r--r--docs/language.rst447
-rw-r--r--docs/macros.rst203
-rw-r--r--docs/semantics.rst441
-rw-r--r--docs/syntax.rst211
9 files changed, 915 insertions, 444 deletions
diff --git a/README.rst b/README.rst
index 1fa7f54..a18cf5c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,6 +5,10 @@ Actinide
.. image:: https://circleci.com/gh/ojacobson/actinide.svg?style=svg
:target: https://circleci.com/gh/ojacobson/actinide
+.. image:: https://readthedocs.org/projects/pip/badge/
+ :target: https://https://actinide.readthedocs.io/
+
+
**An embeddable lisp for Python applications.**
I had `an application`_ in which the ability to extend the application from
@@ -50,6 +54,18 @@ Requirements
Actinide requires Python 3.6 or later.
+Building the documentation requires Sphinx, and should be done in a Python virtual environment:
+
+.. code-block:: bash
+
+ $ python3.6 -m venv .venv
+ $ source .venv/bin/activate
+ $ pip install -r requirements-docs.txt
+ $ make html
+ $ open _build/html/index.html # or any other command to launch a browser
+
+The documentation is also available online at https://actinide.readthedocs.io.
+
************
Installation
************
diff --git a/_templates/globaltoc.html b/_templates/globaltoc.html
new file mode 100644
index 0000000..36894a8
--- /dev/null
+++ b/_templates/globaltoc.html
@@ -0,0 +1,11 @@
+{#
+ basic/globaltoc.html
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: global table of contents.
+
+ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
+{{ toctree(maxdepth=1) }}
diff --git a/_templates/localtoc.html b/_templates/localtoc.html
new file mode 100644
index 0000000..bc0b79d
--- /dev/null
+++ b/_templates/localtoc.html
@@ -0,0 +1,13 @@
+{#
+ basic/localtoc.html
+ ~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: local table of contents.
+
+ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- if display_toc %}
+ <h3><a href="{{ pathto(master_doc) }}">{{ _('This Section') }}</a></h3>
+ {{ toc }}
+{%- endif %}
diff --git a/conf.py b/conf.py
index 3d6d5f2..aa9c288 100755
--- a/conf.py
+++ b/conf.py
@@ -89,7 +89,11 @@ html_theme = 'alabaster'
# further. For a list of options available for each theme, see the
# documentation.
#
-# html_theme_options = {}
+html_theme_options = {
+ 'github_button': True,
+ 'github_user':'ojacobson',
+ 'github_repo': 'actinide',
+}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -103,6 +107,8 @@ html_static_path = ['_static']
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
+ 'globaltoc.html',
+ 'localtoc.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
diff --git a/docs/embedding.rst b/docs/embedding.rst
index f07b0f6..d179baf 100644
--- a/docs/embedding.rst
+++ b/docs/embedding.rst
@@ -78,8 +78,8 @@ will automatically determine the name to bind to:
session.bind_fn(example)
print(*session.run('(example)')) # prints "5"
-Finally, to bind a function returning a tuple of results, call
-``bind_builtin``. This will automatically determine the name to bind to:
+To bind a function returning a tuple of results, call ``bind_builtin``. This
+will automatically determine the name to bind to:
.. code-block:: python
@@ -128,6 +128,11 @@ The symbol must be bound to an instance of the ``Registry`` class from the
def two_values():
return 1, "Two"
+ An.eval('''
+ (begin
+ (define (three-values) (values 1 2 3)))
+ ''')
+
# @An.macro_bind, @An.macro_void, @An.macro_fn, and @An.macro_builtin follow
# the same pattern.
diff --git a/docs/language.rst b/docs/language.rst
index 356b490..c033f65 100644
--- a/docs/language.rst
+++ b/docs/language.rst
@@ -4,446 +4,11 @@ The Actinide Programming Language
.. highlight:: scheme
-*****
-Forms
-*****
+The following documents fully describe the Actinide language, and all of its
+built-in syntactic elements.
-* The basic unit of Actinide syntax.
+.. toctree::
-* The basic unit of Actinide evaluation.
-
-* A program is evaluated by *reducing* forms to produce a final value, applying
- side effects during the reduction.
-
- * Simple forms: literals (and intro to types)
-
- * Integers: an optional leading - sign for negative numbers, followed by a
- sequence of digits and underscores. Represent base-ten values with no
- fractional part. Examples: ``10``, ``-2_049``.
-
- * Decimals: an optional leading - sign for negative numbers, followed
- by a sequence of digits and underscores, followed by a dot, followed
- by a sequence of digits and underscores. Represent base-ten values
- which may have a factional part. Examples: ``10.0``, ``-2_049.501_2``.
-
- * Strings: any sequence of characters other than ``"`` or ``\``,
- enclosed in matching ``"`` marks. The sequences ``\"`` and ``\\`` are
- "escape" sequences, representing a ``"`` or ``\`` character
- respectively. Examples: ``"Hello, world."``, ``"😡💩🚀"``, ``"Quoth
- the raven, \"Four Oh Four.\""``.
-
- * Booleans: the special values meaning "true" and "false." Preferred
- for boolean logic operations. They are ``#t`` for true, and ``#f``
- for false.
-
- * Simple forms: symbols
-
- * Sequences of letters, numbers, and symbols not surrounded by quotes,
- and which are not themselves integers, decimals, or booleans.
-
- * Represent variables and constants in the program's source.
-
- * Evaluation of variables is covered later in this document.
-
- * Examples: ``hello``, ``+``, ``my-🚀``.
-
- * Special mention: comments
-
- * Cannot appear *inside* a string.
-
- * Starts with a ``;``, continues to the end of the line.
-
- * Dropped from the program entirely.
-
- * Examples: ``; this function is extremely spicy.``
-
-* Compound forms: conses and dotted pairs
-
- * An opening ``(``, followed by a head subform, followed by spaces,
- followed by a ``.``, followed by a tail subform, followed by a closing
- ``)``.
-
- * Represents a *cons* with the given head and tail.
-
- * A dotted pair which appears as the head of a dotted pair does not require
- an additional dot.
-
- * Examples: ``(1 . 2)``, ``(1 2 . 3)``, ``(('ll . 'lr) . ('rl . 'rr))``
-
-* Compound forms: lists
-
- * An opening ``(``, followed by a sequence of "subforms" separated by
- spaces, followed by a closing ``)``.
-
- * Subforms may be any form, including another list.
-
- * Represent function application as well as special
-
-* Compound forms: quotes, quasiquotes, and unqoute forms.
-
- * The forms ``'``, `````, ``,``, and ``,@`` represent "quote" forms.
-
- * These are discussed in detail in the Macros section, later on.
-
-**********
-Evaluation
-**********
-
-* When an Actinide program is run, its top-level form is evaluated.
-
-* Evaluation of a form *reduces* the form to a simpler form - ideally, into a
- list of atomic values.
-
-* Every kind of form can be evaluated.
-
-
-******************
-Simple Expressions
-******************
-
-* Evaluation of literals:
-
- * Integers, decimals, strings, booleans evaluate to themselves. The number
- ``1`` or the string ``"Hello, world"`` cannot be reduced any further.
-
-* Evaluation of symbols:
-
- * The symbol is replaced by a value from the current *environment*.
-
- * This is analogous to variable expansion in other languages.
-
- * How do environments get their values? Defines and function application,
- covered below.
-
- * Certain symbols are *built in* and are automatically given values in the
- top-level environment before the program starts.
-
-********************
-Function Application
-********************
-
-* Evaluation of lists:
-
- * A list that starts with the symbols ``begin``, ``values``, ``if``,
- ``lambda``, ``define``, ``define-macro``, or ``quote`` is a *special
- form*, which are covered separately.
-
- * Any other list represents a function application.
-
-* The subforms representing the list elements are evaluated first, left to
- right.
-
-* If the first subform evaluates to a procedure
-
-* During application:
-
- * A new *child* environment is created, with the names of the arguments
- bound to the values from the function application expression. The
- environment captured by the procedure is the *parent* of this new
- environment: any name not found in the *child* environment will be looked
- up in the parent environment instead.
-
- * The body of the function is run as a program, in the newly-created
- environment.
-
- * The result of the last form in the function is the result of the function
- application.
-
-*************
-Special Forms
-*************
-
-Lists that begin with one of the following symbols are evaluated specially.
-
-* ``begin``: A ``begin`` form evaluates a sequence of subforms, reducing to the
- result of the last subform in the sequence. Example:
-
- ::
-
- (begin
- ; define a function...
- (define (f) 1)
- ; ...and call it
- (f))
-
- The forms whose results are discarded are still evaluated for their side
- effects.
-
-* ``values``: A ``values`` form evaluates a sequence of subforms, then reduces
- to those values in the context of the containing form. This allows functions
- to return multiple values. Example:
-
- ::
-
- (begin
- (define (two x) (values x x))
- (= (two 53)))
-
- The ``two`` function returns two values, which are placed in the argument
- positions for the ``=`` function. This program reduces to ``#t`` if run,
- and defines ``two`` as a side effect.
-
-* ``if``: An ``if`` form must include a ``cond`` subform producing exactly one
- value, and either one or two consequent subforms (named ``true`` and
- ``false`` subforms in this document).
-
- * The ``if`` form first evaluates the ``cond`` subform.
-
- * If it evaluates to a true value (``#t``, a non-zero integer, a non-zero
- decimal, a non-empty string, or a non-nil ``cons``), then the ``if``
- form evaluates the ``true`` subform.
-
- * If the ``cond`` subform evaluates to a false value (any other value),
- then the ``if`` form evaluates the ``false`` subform.
-
- * If the ``if`` form does not have a ``false`` subform, the ``if`` form
- evaluates to ``nil`` when the ``cond`` subform evaluates to a false
- value.
-
- * Examples: ``(if #t 1)`` (always equal to ``1``), ``(if some-var "okay"
- "failure")``.
-
-* ``lambda``: A ``lambda`` form defines a procedure, and evaluates to a
- procedure value which can be used to apply the newly-defined procedure.
-
- * Must include a ``formals`` subform, which is generally a list of argument
- names (as symbols). If the formals subform is a bare symbol, or a dotted
- pair whose tail is a symbol, the function has variable arity, and all
- arguments not assigned to a name from the formals list are collected into
- a list and bound to that symbol.
-
- * May include a sequence of body subforms, which are evaluated in order (as
- if by ``begin``) whenever the function is applied.
-
- * Functions capture the environment in effect when they are defined.
- Symbols within the function body can refer to names defined in the
- surrounding lexical context.
-
- * Function bodies are evaluated in a new environment for each application,
- with the symbols representing the arguments bound to the corresponding
- values in the function application form.
-
- * Examples:
-
- ::
-
- (lambda () 1)
-
- This defines a constant function (which takes no arguments) whose
- evaluation is always 1.
-
- ::
-
- (begin
- (define x 5)
- (lambda () x))
-
- This defines a constant function whose evaluation is always the value of
- ``x`` in the top-level environment (initially 5).
-
- ::
-
- (lambda (a b) (+ a b))
-
- This defines a binary function (which takes two arguments) whose
- evaluation is the sum of those arguments. This is a simple replacement
- for the ``+`` function itself, but it illustrates the idea that functions
- can include other functions.
-
- ::
-
- (lambda (a . b) b)
-
- This defines a function which takes one or more arguments, whose
- evaluation is the list of arguments other than the first.
-
-* ``define``: A ``define`` form sets the value of a new binding in the current
- environment. This has two forms:
-
- * ``(define symbol value)``: evaluates the ``value`` subform, and binds the
- result to ``symbol`` in the current environment. Example:
-
- ::
-
- (begin
- ; Bind x to a value
- (define x 5)
- ; Expands x in the same environment
- x)
-
- This program evaluates to ``5``.
-
- * ``(define (name formals...) body...)``: defines a function and binds it
- to ``name`` in the current environemnt.
-
- This is expanded to an equivalent ``lambda`` form, within a ``define``
- form binding the resulting procedure to ``name``. For example:
-
- ::
-
- (define (f a b) (+ a b))
-
- is equivalent to
-
- ::
-
- (define f
- (lambda (a b) (+ a b)))
-
-* ``define-macro``: This has the same syntaxes as the ``define`` form, but it
- binds values to a special "macro table" which is used to transform code prior
- to evaluation. Macros are described later in this document.
-
-* ``quote``: A ``quote`` form must have exactly one form in argument position.
- It evaluates to exactly the argument form, without evaluating it. For example:
-
- ::
-
- (quote (+ 1 2))
-
- evaluates to the list ``(+ 1 2)``. Quote forms are the easiest way to obtain
- unevaluated symbols as values, and are an integral part of the Actinide macro
- system.
-
-*******************
-Loops and Recursion
-*******************
-
-* To loop, a function must recurse. Actinide has no looping primitives other
- than function application.
-
-* Actinide guarantees that functions that recurse in tail position, either
- directly or indirectly, can recurse indefinitely.
-
-* What is tail position?
-
- * Function bodies: the final form of the function is in tail position with
- respect to the function.
-
- * ``begin`` forms: the final subform is in tail position with respect to
- the ``begin`` form.
-
- * ``if`` forms: the ``true`` subform is in tail position with respect to
- the ``if`` form if the ``cond`` subform reduces to a true value. The
- ``false`` subform is in tail position with respect to the ``if`` form if
- the ``cond`` subform reduces to a false value.
-
- * If a form is in tail position with respect to its containing form, it is
- in tail position with respect to *that* form's containing form, and so
- on, out to the nearest ``lambda`` body or to the top level of the program.
-
-* Example:
-
- * A simple, non-tail recursive factorial:
-
- ::
-
- (define (factorial n)
- (if (= n 1)
- 1
- (* n (factorial (- n 1)))))
-
- The ``factorial`` function *is not* called in tail position with respect
- to the body of the ``factorial`` function: After reducing that function
- application, the reduction of the outer ``factorial`` application still
- needs to apply the ``*`` function to the result.
-
- Attempting to evaluate ``(factorial 1000)`` fails due to limits on call
- depth: ``maximum recursion depth exceeded while calling a Python object``
-
- ::
-
- (define (fact n a)
- (if (= n 1)
- a
- (fact (- n 1) (* n a))))
-
- The ``fact`` function *is* called in tail position with respect to the
- body of ``fact``. Specifically, it is in tail position with respect to
- the ``if`` form whenever ``n`` is not equal to ``1``, and the ``if`` form
- is in tail position with respect to the body of the ``fact`` function.
-
- Evaluating ``(fact 1000 1)`` correctly computes the factorial of ``1000``
- on any machine with enough memory to store the result.
-
-******
-Macros
-******
-
-* Before Actinide evaluates a program, it *expands* a program.
-
-* Expansion replaces macros (defined by ``define-macro``, as above).
-
-* A *macro* is an Actinide procedure, as with ``lambda``, which accepts forms
- as arguments and reduces to a new form.
-
-* Macros can be used to define new syntax.
-
-* Macro expansion is recursive: the result of expanding a macro is expanded
- again, which allows macros to produce macro forms.
-
-* Example: The ``let-one`` macro defines a single local variable, with a known
- value, and evaluates a body form in a temporary environment with that
- variable bound.
-
- ::
-
- (define-macro (let-one binding body)
- (begin
- (define name (head binding))
- (define val (head (tail binding)))
- `((lambda (,name) ,body) ,val))))
-
- To use this macro, apply it as if it were a function:
-
- ::
-
- (let-one (x 1) x)
-
- The macro procedure accepts the forms ``(x 1)`` and ``x``, unevaluated, as
- arguments, and substitutes them into a *quasiquoted* form, which is used as a
- template. The three *unquoted* parts (``,name``, ``,body``, and ``val``) are
- replaced by evaluating the symbols in the context of the macro procedure, and
- expand to the relevant parts of the input forms.
-
- The returned form is approximately
-
- ::
-
- ((lambda (x) x) 1)
-
- and evaluates as such.
-
- This program evaluates to 1, but *does not* bind ``x`` in the top-level
- environment.
-
-* Actinide macros are *not hygienic*. A quoted symbol in the macro body will be
- evaluated in the location where the macro is expanded, with full access to
- the environment at that location. Similarly, symbols defined in the macro
- will be fully visible to code running in the environment where the macro is
- expanded.
-
-* Macros often use quote notation to build the returned form. Quote notation is
- ultimately a sequence of ``quote`` forms. However, Actinide supports
- *quasiquote* notation to simplify the creation of nested quoted forms
- containing unquoted parts.
-
- * A quasiquote form begins with `````. If the form contains no unquoted
- parts, this will quasiquote each subform, terminating by quoting each
- symbol or literal form and constructing a new list with the resulting
- quoted forms. ```(a b)`` expands to ``('a 'b)``.
-
- * Within a quasiquote form, an *unquote* form prevents the following form
- from being quoted. An unquote form begins with ``,``, followed by a
- single form (often, but not always, a single symbol). ```(a ,b c)``
- expands to ``('a b 'c)``.
-
- * Within a quasiquote form, an *unquote-splicing* form prevents the
- following form from being quoted. An unquote-splicing form begins with
- ``,@``, followed by a single form, which must evaluate to a list. The
- elements of that list are grafted into the resulting form. Given
- ``(define x (list 1 2))``, the form ```(a ,@x b)`` expands to ``('a 1 2
- 'b)``.
-
-* Macros defined inside of a function body are not visible to the top-level
- expander.
+ syntax
+ semantics
+ macros
diff --git a/docs/macros.rst b/docs/macros.rst
new file mode 100644
index 0000000..f544d93
--- /dev/null
+++ b/docs/macros.rst
@@ -0,0 +1,203 @@
+.. _macros:
+
+######
+Macros
+######
+
+This section describes Actinide's macro facility, which transforms programs
+between parsing and evaluation. Macros provide a powerful way to extend Actinide's syntax.
+
+.. warning::
+
+ Actinide's macro expansion facility is broadly inspired by Common Lisp's,
+ and implements *non-hygienic* macros: symbols generated by macro expansion
+ can conflict with symbols defined in the context where the macro is
+ expanded in both directions.
+
+ I would like to replace this with a macro expander based on Scheme's, but I
+ can't promise that I'll ever get around to it. Writing macros using
+ Actinide's macro system is fraught with minor but irritating problems
+ related to symbol capture, and macros should use user-provided symbols as
+ much as possible to avoid interacting with the environment at the expansion
+ site.
+
+.. warning::
+
+ Macro expansion is fully completed before any evaluation occurs. Programs
+ can define macros for future programs run in the same environment to use,
+ but not for themselves. The following does not expand the "remove-one"
+ macro:
+
+ .. code-block:: scheme
+
+ (begin
+ (define-macro (remove-one a b) b)
+ (remove-one 1 2))
+
+ Instead, that program attempts to evaluate an undefined ``remove-one``
+ function as an ordinary procedure, and fails. The macro binding introduced
+ in this program would be available to future programs run in the same
+ environment.
+
+ The Actinide REPL runs each form as an independent program, so
+ interactively defining macros in the REPL behaves in an intuitive way.
+ Programs that embed Actinide must take care to provide sensible ways to
+ load macro definitions, as well as any supporting functions those macro
+ definitions require. The embedding guide's ``An.eval`` primitive is the
+ recommended way to pre-load definitions into a session, as each ``eval``
+ binding is run as an independent program, sharing a top-level environment
+ with future programs run in the same session.
+
+The :ref:`define-macro` form, introduced in the :ref:`semantics` chapter,
+creates macro transformer bindings. In brief, a *macro transformer* is an
+ordinary Actinide procedure, whose result is an unevaluated *form*, rather than
+a value. The arguments to a macro transformer are also forms, which the macro
+transformer can pick apart and manipulate.
+
+When Actinide's expansion step encounters a list form whose head is a symbol
+matching a macro transformer in the top-level environment, the form is removed
+from the program. The head is discarded (it only identifies the macro), and the
+remaining subforms are passed, un-evaluated, to the macro transformer as
+arguments. The result of the macro transformer is inserted into the program in
+place of the removed macro form.
+
+The following example illustrates, by defining a new ``let-one`` special form. This special form has the following syntax:
+
+.. code-block:: scheme
+
+ (let-one (name form) body)
+
+When it's reduced, it creates a new environment in which the result of reducing
+``form`` is bound to the variable ``name``, then evaluates ``body`` in that
+environment.
+
+.. code-block:: scheme
+
+ (define-macro (let-one binding body)
+ (begin
+ (define name (head binding))
+ (define val (head (tail binding)))
+ `((lambda (,name) ,body) ,val))))
+
+To use this macro, apply it as if it were a function:
+
+.. code-block:: scheme
+
+ (let-one (x 1) (+ x 2))
+
+The macro transformer receives the forms ``(x 1)`` and ``x``, unevaluated, as
+arguments, and substitutes them into a :ref:`quasiquoted <quasiquotes>` form,
+which is used as a template for the result of the macro. The three *unquoted*
+parts (``,name``, ``,body``, and ``val``) are replaced by evaluating the
+symbols in the context of the macro procedure, and expand to the relevant parts
+of the input forms.
+
+The returned form is equivalent to
+
+.. code-block:: scheme
+
+ ((lambda (x) (+ x 2) 1)
+
+This program evaluates to 3, without binding ``x`` in the current environment.
+
+.. _quasiquotes:
+
+~~~~~~~~~~~
+Quasiquotes
+~~~~~~~~~~~
+
+Actinide provides three quote-like special forms which are fully handled by the
+macro expander, and which are meant to ease the development of macros.
+
+quasiquote
+~~~~~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ `form
+ (quasiquote form)
+
+Evaluation of a quasiquote form produces an expression that reconstructs
+``form``. If ``form`` contains no ``unquote`` or ``unquote-splicing`` forms,
+then ```form`` produces a form which evaluates to the equivalent of ``'form``.
+
+The exact expansion of quasiquote forms produces expressions which, when
+evaluated, produce equivalents to simpler quoted forms. However, the exact
+result of a quasiquoted form is generally a form which, when evaluated, calls a
+sequence of built-in procedures to construct lists, rather than the lists
+themselves. For example, the form ```(+ 1 2)`` ultimately expands to
+
+.. code-block:: scheme
+
+ (cons '+ (cons '1 (cons '2 '())))
+
+which evaluates to ``'(+ 1 2)``, rather than expanding to ``'(+ 1 2)`` directly.
+
+unquote
+~~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ ,form
+ (unquote form)
+
+This form *must* appear within a ``quasiquote`` form. When the containing
+``quasiquote`` form is expanded, the unquoted form is placed in the result
+without quoting, so that it will be evaluated normally when the quasiquote form
+is evaluated. The result of evaluating ``form`` will be inserted into the
+result of the ``quasiquote`` form in place of the ``unquote`` form.
+
+Example:
+
+.. code-block:: scheme
+
+ (begin
+ (define x 5)
+ `(+ ,x y))
+
+This evaluates to a form equivalent to
+
+.. code-block:: scheme
+
+ '(+ 5 y)
+
+unquote-splicing
+~~~~~~~~~~~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ ,@form
+ (unquote-splicing form)
+
+This form *must* appear within a ``quasiquote`` form. When the containing
+``quasiquote`` form is expanded, each form guarded by an ``unquote-splicing``
+form will be inserted unquoted. The guarded form must evaluate to a list, which
+is spliced into the ``quasiquote`` form's result. For example, given
+
+.. code-block:: scheme
+
+ (define x (list 1 2))
+
+then these forms
+
+.. code-block:: scheme
+
+ ; unquote
+ `(+ ,x)
+ ; unquote-splicing
+ `(+ ,@x)
+
+expand to, respectively, forms equivalent to
+
+.. code-block:: scheme
+
+ ; unquote
+ '(+ '(1 2))
+ ; unquote-splicing
+ '(+ 1 2)
diff --git a/docs/semantics.rst b/docs/semantics.rst
new file mode 100644
index 0000000..9cc19a1
--- /dev/null
+++ b/docs/semantics.rst
@@ -0,0 +1,441 @@
+.. _semantics:
+
+#########
+Semantics
+#########
+
+.. highlight:: scheme
+
+Forms are also the most basic unit of Actinide evaluation. Execution of an
+Actinide program proceeds by *reducing* one form to a simpler result, until
+only a single irreducible form is left (which is the program's result).
+
+Most Actinide programs consist of a top-level compound form, which must be
+fully reduced to run the program to completion. The following sections describe
+the mechanism and results of reducing each kind of form. In general, evaluation
+proceeds by reducing the inner-most, left-most unreduced form, iteratively,
+until all forms have been reduced.
+
+********
+Literals
+********
+
+Literal forms reduce to themselves, unchanged. The following forms are
+considered literal forms:
+
+* Integers
+* Decmials
+* Strings
+* Booleans
+
+For example, the result of reducing ``1`` is ``1``.
+
+*******
+Symbols
+*******
+
+Symbols, other than those that are part of :ref:`special forms <special
+forms>`, represent variables in Actinide programs, and reduce to the values of
+those variables in the current *environment*.
+
+In an environment where a symbol has a value, the reduction of that symbol is
+the value it's bound to. In an environment where a symbol is not bound to any
+value, the reduction of that symbol produces an error and stops the computation.
+
+For example, in an environmet where the symbol ``x`` is bound to ``5``, the
+result of reducing ``x`` is ``5``.
+
+An Actinide program is run in an initial *top-level environment*, which comes
+pre-populated with bindings for all of Actinide's built-in functions and
+values, plus any values placed there by the host program. As Actinide reduces a
+program, the bindings in that initial environment can change, and additional
+environments may be created. The *current environment* is controlled by the
+:ref:`lambda` form and by :ref:`procedure application`.
+
+.. _special forms:
+
+*************
+Special forms
+*************
+
+Lists that begin with one of the following symbols are evaluated specially.
+
+~~~~~
+quote
+~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (quote form)
+
+A ``quote`` form guards another form from evaluation. The result of reducing a
+quote form is exactly the guarded ``form``. This allows forms that may have
+special meaning, such as lists, to be embedded in Actinide programs as literal
+values, stripped of their special meaning.
+
+.. _begin:
+
+~~~~~
+begin
+~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (begin [form-1 ... form-n])
+
+A ``begin`` form fully evaluates each subform in left-to-right order, then
+reduces to the value of the final subform. This allows for forms with side
+effects to be evaluated (and their results ignored) before evaluating a final
+form that produces a result.
+
+An empty ``begin`` form evaluates to the empty list.
+
+Example:
+
+.. code-block:: scheme
+
+ (begin
+ ; define a function...
+ (define (f) 1)
+ ; ...and call it
+ (f))
+
+.. _if:
+
+~~
+if
+~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (if cond if-true)
+ (if cond if-true if-false)
+
+An ``if`` form conditionally evaluates one of two forms based on the result of
+a condition. The ``cond`` form is fully evaluated first; if it reduces to a
+true value, then the ``if-true`` form is evaluated and the ``if`` form reduces
+to its result; otherwise, the ``if-false`` form is evaluated and the ``if``
+form reduces to its result. In either case, the other form is discared without
+evaluation.
+
+An ``if`` form without an ``if-false`` form reduces to nil if the ``cond`` form reduces to a false value.
+
+The following values are false:
+
+* the empty list
+* ``#f``
+* integer and decimal zeroes
+* empty strings
+* empty vectors
+
+All other values are true.
+
+Example:
+
+.. code-block:: scheme
+
+ (if #t 'was-true 'was-false)
+
+ (if (goldback-conjecture)
+ "Eureka!")
+
+.. _lambda:
+
+~~~~~~
+lambda
+~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (lambda formals [body-1...body-n])
+
+Defines a procedure taking arguments described by the ``formals`` form, whose
+application will evaluate the ``body`` forms in order and will reduce to the
+result of the last form.
+
+The ``formals`` form must have one of the following structures:
+
+* A list of symbols, each of which will be bound to a single argument when the
+ procedure is applied, in the order listed.
+
+* An improper list of symbols. Each symbol other than the final tail symbol
+ will be bound to an argument from the procedure application; the final tail
+ symbol will be bound to a list of all arguments that were not bound to any
+ other symbol.
+
+* A single symbol, which will be bound to a list of the arguments when the
+ procedure is applied.
+
+A ``lambda`` form reduces to a newly-created procedure value whose body is the
+list of body forms and whose formal argument list is the formals.
+
+Each procedure captures the environment in effect when the ``lambda`` form is
+evaluated, allowing the procedure body to see variables that were visible at
+that time, even if the procedure outlives the context where that environment is
+defined.
+
+Each time a procedure is applied, Actinide creates a new environment that
+inherits from the captured environment and binds the values of arguments from
+the procedure application to the symbols named in the procedure's ``formals``.
+This is the primary mechanism for creating new environments in Actinide.
+Procedure application then evaluates the body forms, in that new environment,
+in left-to-right order. The result of the final form is the result of the
+procedure application. (In fact, procedures whose bodies consist of multiple
+forms, or of no forms at all, are converted to a procedure whose body is a
+single ``begin`` form.)
+
+Examples:
+
+.. code-block:: scheme
+
+ ; Creates a constant function of zero arguments, which always
+ ; evaluates to 1.
+ (lambda () 1)
+
+ ; Defines a variable in the current environment (as discussed
+ ; below), then creates a function of zero arguments that returns
+ ; that variable. Initially, it will always return 5, but if the
+ ; value of x is changed in the outer environment, the function's
+ ; return value will change as well.
+ (begin
+ (define x 5)
+ (lambda () x))
+
+ ; Defines a function of two arguments, a and b, whose result is
+ ; the sum of those arguments. This is a simple alias for the +
+ ; built-in function, illustrating the idea that functions can
+ ; call other functions.
+ (lambda (a b) (+ a b))
+
+ ; Defines a function that takes one or more arguments, with the
+ ; first argument bound to a (and ignored) and the list of
+ ; remaining arguments bound to b. This always returns b
+ ; unchanged, and throws away a.
+ (lambda (a . b) b)
+
+ ; Defines a function that takes any number of arguments, and
+ ; returns them as a list. This is a simple alias for the list
+ ; built-in function.
+ (lambda a a)
+
+.. _define:
+
+~~~~~~
+define
+~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (define symb form)
+ (define signature [body-1...body-n])
+
+A define form creates a new variable in the current environment, and binds a
+value to that variable. There are two variations on this form: simple
+definition and procedure definition.
+
+In the first form, the ``symb`` subform must be a single symbol. The ``form``
+subform is fully reduced, and the resulting value is bound to the variable
+``symb`` in the current environment. For example:
+
+.. code-block:: scheme
+
+ (begin
+ ; Defines a variable, x, whose initial value is 5.
+ (define x 5)
+ ; Evaluates to the value of x.
+ x)
+
+In the second, the ``signature`` subform must be a procedure signature: a list
+or improper list of symbols. The first element of that list is the name the
+procedure will be bound to, while the rest of that list is treated as the
+``formals`` form as described under :ref:`lambda`. The list of ``body`` forms become
+the resulting procedure's body, as usual.
+
+Under the hood, the second form is translated into the first automatically -
+the form
+
+.. code-block:: scheme
+
+ (define (sum a b) (+ a b))
+
+is exactly equivalent to the form
+
+.. code-block:: scheme
+
+ (define sum
+ (lambda (a b) (+ a b)))
+
+However, when the option is available, procedure definition should be preferred
+as it's generally more readable.
+
+~~~~~~
+values
+~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (values [body-1...body-n])
+
+Where most forms reduce to a single value, the ``values`` form reduces to a
+sequence of values, in place. This allows a function or any other form to
+reduce to multiple distinct values, which can be inserted into other forms.
+
+The body forms are evaluated left-to-right, and the ``values`` form reduces to
+the resulting values, left-to-right.
+
+Example:
+
+.. code-block:: scheme
+
+ (begin
+ ; A function which returns two values, both equal to its
+ ; sole argument
+ (define (two x) (values x x))
+ ; = accepts two values and compares them.
+ (= (two 53)))
+
+.. _define-macro:
+
+~~~~~~~~~~~~
+define-macro
+~~~~~~~~~~~~
+
+Syntax:
+
+.. code-block:: scheme
+
+ (define-macro symb form)
+ (define-macro signature [body-1...body-n])
+
+A ``define-macro`` form creates a new :ref:`macro transformer <macros>`
+function in the current environment's macro table. This is identical to the
+:ref:`define` form, but the resulting binding is not visible as a variable, and
+affects macro expansion of Actinide programs. Macro bindings using the first
+form must bind the symbol to a procedure or built-in function producing exactly
+one result.
+
+.. warning::
+
+ A ``define-macro`` form which appears within a procedure body will create a
+ macro in the environment created when the procedure is applied. These
+ macros are **never** visible to the macro expander, and will have no effect.
+
+.. _procedure application:
+
+*********************
+Procedure application
+*********************
+
+Any list which is not empty, and not a :ref:`special form <special forms>`, is
+a procedure application, applying either a built-in procedure (provided by
+Actinide or by the host program) or a procedure defined using the :ref:`lambda`
+special form or any of its :ref:`equivalents <define>`.
+
+Syntax:
+
+.. code-block:: scheme
+
+ (fn [arg-1...arg-n])
+
+The subforms of a list form are evaluated from left to right. The ``fn``
+subform must evaluate to a procedure; the remaining ``body`` forms are
+evaluated to produce the values of arguments to that procedure. Once all of the
+subforms have been evaluated, the procedure is applied to its arguments, and
+the procedure application itself reduces to the result of the applied procedure.
+
+During the application of a procedure,
+
+1. A new *child* environment is created from the procedure's captured
+ environment. In this environment, any name not defined in the child
+ environment is looked up in the captured environment instead.
+
+2. The values of the arguments from the function application form are bound to
+ the names given by the procedure's formal arguments list.
+
+3. The procedure's body forms are evaluated from left to right in the child
+ environment.
+
+4. The result of the last form in the procedure body is used as the result of
+ the function application.
+
+~~~~~~~~~~~~~~~~~~~
+Loops and Recursion
+~~~~~~~~~~~~~~~~~~~
+
+Actinide has no primitives dedicated to repeating parts of a program. To loop,
+a procedure must recurse. Actinide guarantees that recursion in *tail position*
+can proceed arbitrarily far without exhausting any resources solely due to the
+number of recursive calls. Actinide guarantees tail recursion.
+
+The following forms are considered to be in tail position:
+
+* The final form of a :ref:`procedure body <lambda>` is in tail position with
+ respect to the application of that procedure.
+
+* The final form of a :ref:`begin` form is in tail position with respect to the
+ ``begin`` form itself.
+
+* The ``if-true`` form of an :ref:`if` form whose condition is true, and the
+ ``if-false`` form of an ``if`` form whose condition is not true, is in tail
+ position with respect to the ``if`` form.
+
+* If a form is in tail position with respect to another form, it is also in
+ tail position for any form that form is in the tail position of, and so on
+ outwards until the form is either in tail position with respect to the root
+ of the program or a form is found for which the containing form is not in
+ tail position.
+
+As an example, the following implementation of the factorial algorithm is
+recursive, but the recursion does not appear in tail position (it is not *tail
+recursive*):
+
+.. code-block:: scheme
+
+ (define (factorial n)
+ (if (= n 1)
+ 1
+ (* n (factorial (- n 1)))))
+
+The ``factorial`` function *is not* called in tail position with respect to the
+body of the ``factorial`` function: After reducing the inner application of
+``factorial``, the reduction of the outer ``factorial`` application must
+continue so that it can apply the ``*`` function to the result.
+
+Attempting to evaluate ``(factorial 1000)`` fails due to limits on call depth:
+``maximum recursion depth exceeded while calling a Python object``
+
+.. note::
+
+ This warning leaks some implementation details, obviously. The exact
+ failure mode should not be relied on; the key property is that
+ deeply-recursive programs will raise an error when they exhaust the
+ implementation's resources.
+
+The following implementation of the factorial algorithm *is* tail-recursive:
+
+.. code-block:: scheme
+
+ (define (fact n a)
+ (if (= n 1)
+ a
+ (fact (- n 1) (* n a))))
+
+The ``fact`` function is called in tail position with respect to the body of
+``fact``. Specifically, it is in tail position with respect to the ``if`` form
+whenever ``n`` is not equal to ``1``, and the ``if`` form is in tail position
+with respect to the body of the ``fact`` function.
+
+Evaluating ``(fact 1000 1)`` correctly computes the factorial of ``1000`` on
+any machine with enough memory to store the result.
diff --git a/docs/syntax.rst b/docs/syntax.rst
new file mode 100644
index 0000000..b84e0ae
--- /dev/null
+++ b/docs/syntax.rst
@@ -0,0 +1,211 @@
+######
+Syntax
+######
+
+.. highlight:: scheme
+
+The most basic unit of Actinide's syntax is the *form*. An Actinide program
+consists of a single top-level form, which may include subforms and
+sub-subforms within it nested arbitrarily deeply.
+
+********
+Comments
+********
+
+An Actinide program may contain comments. Comments are removed during parsing
+and are not technically forms, but they're included here for completeness. A comment begins with a ``;`` and continues to the next newline character or until the end of the program, whichever comes first.
+
+Examples:
+
+* ``; this is a comment.``
+
+*****
+Atoms
+*****
+
+The following forms are *atomic* - they do not contain any subforms, and can be
+reduced in a single step to a final value.
+
+~~~~~~~~
+Integers
+~~~~~~~~
+
+An Actinide integer represents a mathematical integer: a precise number with no
+fractional part, which may be positive, negative, or zero. Actinide integers do
+not have a fixed range - there is no built-in maximum or minimum integer.
+
+The syntax of an integer consists of an optional leading ``-`` sign for
+negative integers, followed by any sequence of digits and underscores.
+Underscores should be used to separate thousands.
+
+Examples:
+
+* ``10``
+* ``-2_049``
+
+.. note::
+
+ Practically, Actinide integers are represented by Python ``int`` objects,
+ and share their characteristics. This is not part of their specification,
+ but the formal properties of Actinide constracts aren't fully separable
+ from the implementation at this time.
+
+~~~~~~~~
+Decimals
+~~~~~~~~
+
+An Acdinide decimal represents a precise base-ten fractional value with a
+finite number of decimal places. Actinide decimals do not have a fixed limit on
+range or precision.
+
+The syntax of a decimal consists of an optional leading ``-`` sign for negative
+decimal numbers, followed by an optional sequence of digits and underscores for
+the integral part, followed by a ``.``, followed by an optional sequence of
+digits and underscores for the fractional part, followed by an optional
+exponent part consisting of an ``e`` and a sequence of digits and underscores.
+
+A decimal form *must* have a non-empty integral part or a non-empty fractional
+part. As with integers, underscores should be used as thousands separators.
+
+Examples:
+
+* ``0.0``
+* ``-2_049.501_2``
+* ``2e10``
+
+.. note::
+
+ Practically, Actinide decimals are represented by Python
+ ``decimal.Decimal`` values in the default decimal context. I haven't fully
+ fleshed out the Actinide semantics of decimal operations, so the Python
+ semantics leak through. This means that, for example, there is a negative
+ zero (which is equal to zero), and that ``1e1`` and ``10`` are different
+ (but equal) values.
+
+~~~~~~~
+Strings
+~~~~~~~
+
+An Actinide string represents a sequence of Unicode characters.
+
+The syntax of a string consists of a leading ``"``, followed by any sequence of
+unescaped characters or escaped characters, followed by a trailing ``"``. An
+escaped character is either the sequence ``\"`` or the sequence ``\\``; an
+unescaped character is any Unicode character other than ``\`` or ``"``. The
+enclosing quote marks and escape marks are not part of the string's value, and
+are removed during parsing.
+
+Line breaks and non-printing characters can appear within a string.
+
+Examples:
+
+* ``"Hello, world."``
+* ``"😡💩🚀"``
+* ``"Quoth the raven, \"Four Oh Four.\""``.
+
+.. note::
+
+ As with most other Actinide primitives, strings are implemented directly on
+ top of a common Python type: ``str`` itself. The Python representation is
+ not part of the language, but does leak through in places.
+
+~~~~~~~~
+Booleans
+~~~~~~~~
+
+A boolean value represents one of two logical states: true (represented by
+exactly ``#t``) and false (``#f``).
+
+~~~~~~~
+Symbols
+~~~~~~~
+
+Symbols represent variables and special keywords in an Actinide program.
+
+The syntax of a symbol is a sequence of unicode characters other than quotes,
+semicolons, tabs, spaces, and newlines, which is not an integer, decimal, or
+boolean.
+
+Examples:
+
+* ``x``
+* ``if``
+* ``+``
+* ``my-🚀``
+
+**************
+Compound Forms
+**************
+
+The following forms consist of both the compound form itself and a sequence of
+subforms.
+
+~~~~~
+Lists
+~~~~~
+
+Lists represent most kinds of Actinide syntax other than atoms.
+
+The syntax of a list consists of an opening ``(``, followed by zero or more
+subforms, separated by spaces, tabs, or newlines, followed by a closing ``)``.
+The subforms of a list can be any Actinide form, including another list.
+
+Examples:
+
+* ``(foo)``
+* ``()``
+* ``(1 a #f)``
+
+~~~~~~
+Conses
+~~~~~~
+
+Conses represent pairs of forms.
+
+The syntax of a dotted pair consists of an opening ``(``, followed by a *head*
+form, followed by a ``.``, followed by a *tail* form, followed by a closing
+``)``. A dotted pair appearing as the tail of a dotted pair does not need to be
+enclosed in parentheses, and can be represented by removing the preceding
+``.``, instead.
+
+Examples:
+
+* ``(1 . 2)``
+* ``(1 2 . 3)``
+* ``((ll . lr) . (rl . rr))``
+
+Conses whose tail form is the empty list are themselves lists. A cons whose
+tail form is not a list is an *improper list*.
+
+~~~~~~
+Quotes
+~~~~~~
+
+A quote form prevents the evaluation of its contained form.
+
+The syntax of a quote form is either a list beginning with the symbol ``quote``
+and containing exactly two subforms, or a leading ``'`` followed by a single
+form (which is exactly equivalent to ``(quote form)``).
+
+Examples:
+
+* ``'()``, ``(quote ())``
+* ``'a``, ``(quote a)``
+* ``'(1 . 2)``, ``(quote (1 . 2))``
+
+~~~~~~~~~~~
+Quasiquotes
+~~~~~~~~~~~
+
+Actinide has a fully-featured :ref:`macro system <macros>`. To support the
+macro system, the language includes a system for constructing syntactic forms
+programmatically. The following special forms are part of that system:
+
+* ```form``, ``(quasiquote form)``
+* ``,form``, ``(unquote form)``
+* ``,@form``, ``(unquote-splicing form)``
+
+Full discussion of quasiquoted forms is covered in the section on macros. These
+forms cannot be reduced, and will generally raise an error if they're
+evaluated, but they're normally eliminated during macro expansion before
+evaluation.