[Nickle] nickle: Branch 'master' - 6 commits

Keith Packard keithp at keithp.com
Mon Dec 14 14:03:25 PST 2020


 Makefile.am                              |    2 
 configure.ac                             |    8 
 debian/changelog                         |   13 
 debian/control                           |    2 
 debian/rules                             |    8 
 doc/tutorial/Makefile.am                 |   57 +-
 doc/tutorial/advanced/concurrency.adoc   |  244 +++++++++++
 doc/tutorial/advanced/concurrency.sgml   |  277 -------------
 doc/tutorial/advanced/continuations.adoc |   64 +--
 doc/tutorial/advanced/copying.adoc       |  159 +++----
 doc/tutorial/advanced/exceptions.adoc    |  110 +++++
 doc/tutorial/advanced/exceptions.sgml    |  110 -----
 doc/tutorial/advanced/namespaces.adoc    |   92 ++++
 doc/tutorial/advanced/namespaces.sgml    |  100 ----
 doc/tutorial/basics/command.adoc         |  153 +++----
 doc/tutorial/basics/invoke.adoc          |   36 +
 doc/tutorial/basics/invoke.sgml          |   55 --
 doc/tutorial/builtins/io.adoc            |  208 ++++++++++
 doc/tutorial/builtins/io.sgml            |  219 ----------
 doc/tutorial/builtins/math.adoc          |  161 +++----
 doc/tutorial/builtins/strings.adoc       |  129 ++++++
 doc/tutorial/builtins/strings.sgml       |  138 ------
 doc/tutorial/intro/expressions.adoc      |  257 ++++++++++++
 doc/tutorial/intro/expressions.sgml      |  283 -------------
 doc/tutorial/intro/functions.adoc        |   78 +--
 doc/tutorial/intro/statements.adoc       |  262 ++++++++++++
 doc/tutorial/intro/statements.sgml       |  270 -------------
 doc/tutorial/intro/variables.adoc        |  632 ++++++++++++++-----------------
 doc/tutorial/nickle-tutorial.adoc        |   79 +++
 doc/tutorial/nickle-tutorial.sgml        |  115 -----
 doc/tutorial/tour/tour.adoc              |   80 ++-
 math.5c                                  |    5 
 32 files changed, 2106 insertions(+), 2300 deletions(-)

New commits:
commit fda1efc2ac37de03e385b4348a5d181a474d4145
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Dec 14 13:29:32 2020 -0800

    Version 2.88

diff --git a/configure.ac b/configure.ac
index 6729419..9c363ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,8 +6,8 @@ dnl for licensing information.
 
 AC_PREREQ([2.69])
 
-AC_INIT([nickle],[2.87],[http://nickle.org],[nickle])
-RELEASE_DATE="2020-09-01"
+AC_INIT([nickle],[2.88],[http://nickle.org],[nickle])
+RELEASE_DATE="2020-12-14"
 AC_CONFIG_SRCDIR([nickle.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR(.)
diff --git a/debian/changelog b/debian/changelog
index 2a9594d..74c0d90 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+nickle (2.88) unstable; urgency=medium
+
+  * Switch tutorial to asciidoctor. Closes: #976535.
+
+ -- Keith Packard <keithp at keithp.com>  Mon, 14 Dec 2020 13:28:22 -0800
+
 nickle (2.87) unstable; urgency=medium
 
   * Don't install Makefile and Makefile.in. Closes: #958110.
commit 089c027566db64714211221ab8f345c1cd250632
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Dec 14 13:23:26 2020 -0800

    doc/tutorial: Switch to asciidoctor
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index ac6070d..6729419 100644
--- a/configure.ac
+++ b/configure.ac
@@ -98,9 +98,9 @@ AC_CHECK_FUNCS(unsetenv setenv putenv gettimeofday hstrerror select)
 AC_CHECK_FUNCS(sigaction sigrelse sigignore setrlimit getrlimit)
 AC_CHECK_FUNCS(dlopen dlsym dlerror dlclose)
 
-AC_PATH_PROGS([DOCBOOK2PDF],[docbook2pdf])
+AC_PATH_PROGS([ASCIIDOCTORPDF],[asciidoctor-pdf])
 
-AM_CONDITIONAL(HASDOCBOOK,test -n "$DOCBOOK2PDF")
+AM_CONDITIONAL(HASASCIIDOCTORPDF,test -n "$ASCIIDOCTORPDF")
 
 AC_FUNC_GETPGRP
 
diff --git a/debian/control b/debian/control
index b3f5666..5cc1294 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: interpreters
 Priority: optional
 Maintainer: Keith Packard <keithp at keithp.com>
 Homepage: https://nickle.org
-Build-Depends: debhelper (>= 11), libreadline-dev, docbook-utils, bison, flex
+Build-Depends: debhelper (>= 11), libreadline-dev, ruby-asciidoctor-pdf, bison, flex
 Standards-Version: 4.2.1
 
 Package: nickle
diff --git a/doc/tutorial/Makefile.am b/doc/tutorial/Makefile.am
index e4a1bd0..855cf95 100644
--- a/doc/tutorial/Makefile.am
+++ b/doc/tutorial/Makefile.am
@@ -1,37 +1,32 @@
 
-SGMLFILES=nickle-tutorial.sgml
-PDFFILES=$(SGMLFILES:.sgml=.pdf)
+ADOCFILES=nickle-tutorial.adoc
+PDFFILES=$(ADOCFILES:.adoc=.pdf)
 
 PDF_DATE=$(shell date -ud '$(RELEASE_DATE)')
 
-.sgml.pdf:
-	docbook2tex $< && \
-	pdfjadetex '\pdfinfo{/CreationDate($(PDF_DATE))/ModDate($(PDF_DATE))}\input{$*.tex}' >/dev/null && \
-	pdfjadetex '\pdfinfo{/CreationDate($(PDF_DATE))/ModDate($(PDF_DATE))}\input{$*.tex}' >/dev/null && \
-	pdfjadetex '\pdfinfo{/CreationDate($(PDF_DATE))/ModDate($(PDF_DATE))}\input{$*.tex}' >/dev/null && \
-	sed -i '/^\/ID \[<[0-9A-F][0-9A-F]*> <[0-9A-F][0-9A-F]*>\]/d' $@ && \
-	rm $*.aux $*.log *$.out *$.tex
-
-SGMLINC= \
-	tour/tour.sgml \
-	basics/invoke.sgml \
-	basics/command.sgml \
-	intro/variables.sgml \
-	intro/expressions.sgml \
-	intro/statements.sgml \
-	intro/functions.sgml \
-	builtins/io.sgml \
-	builtins/math.sgml \
-	builtins/strings.sgml \
-	advanced/copying.sgml \
-	advanced/namespaces.sgml \
-	advanced/exceptions.sgml \
-	advanced/concurrency.sgml \
-	advanced/continuations.sgml
-
-EXTRA_DIST=$(SGMLFILES) $(SGMLINC)
-
-if HASDOCBOOK
+.adoc.pdf:
+	asciidoctor-pdf -o $@ $<
+
+ADOCINC= \
+	tour/tour.adoc \
+	basics/invoke.adoc \
+	basics/command.adoc \
+	intro/variables.adoc \
+	intro/expressions.adoc \
+	intro/statements.adoc \
+	intro/functions.adoc \
+	builtins/io.adoc \
+	builtins/math.adoc \
+	builtins/strings.adoc \
+	advanced/copying.adoc \
+	advanced/namespaces.adoc \
+	advanced/exceptions.adoc \
+	advanced/concurrency.adoc \
+	advanced/continuations.adoc
+
+EXTRA_DIST=$(ADOCFILES) $(ADOCINC)
+
+if HASASCIIDOCTORPDF
 
 all-local: $(PDFFILES)
 
@@ -39,7 +34,7 @@ clean-local:
 	$(RM) -f $(PDFFILES)
 
 
-$(PDFFILES): $(SGMLINC)
+$(PDFFILES): $(ADOCINC)
 
 doc_DATA = $(PDFFILES)
 
diff --git a/doc/tutorial/advanced/concurrency.adoc b/doc/tutorial/advanced/concurrency.adoc
new file mode 100644
index 0000000..a9a53b3
--- /dev/null
+++ b/doc/tutorial/advanced/concurrency.adoc
@@ -0,0 +1,244 @@
+
+= Threads and Mutual Exclusion in Nickle
+
+== Basic threading
+
+Threads provide concurrent processing of calculations.
+They are created with the `fork` operator, which spawns a child thread to evaluate its argument and returns it as a variable of the first-class type ``thread``: 
+// <synopsis>
+// fork <literal>expr</literal>
+// </synopsis>
+
+The thread it returns is typically stored like this: 
+
+----
+
+thread t = fork x!;
+----
+
+In the above example, `fork` immediately returns a thread, which is stored in ``t``.
+That thread will calculate the factorial of `x` in the background while the program continues; when the calculation is finished it will block and wait for the parent thread (the one that forked it) to kill, join, or otherwise recognize it. 
+
+__Threads share names__; if a thread changes the value of a variable, that change will occur in the other threads as well.
+See Mutual exclusion below. 
+
+== Thread functions
+
+The builtin namespace Thread has functions for manipulating threads once they have been forked. 
+
+=== Kill
+// <synopsis>
+// int kill ( thread t, ... )
+// </synopsis>
+
+Kills the threads it takes as arguments, regardless of whether or not they are finished, and returns the number of threads successfully killed. 
+
+=== Join
+// <synopsis>
+// poly join ( thread t )
+// </synopsis>
+
+Waits for thread `t` to finish and returns the value of its expression.
+This is how to get the value back out of a thread.
+Once joined, the thread will dissappear.
+For example, 
+
+----
+
+thread t = fork 1000!;
+# something else...
+printf("1000! = %d\n",Thread::join(t));
+----
+
+will execute 'something else' while `t` runs, then wait for it to complete and print out its value. 
+
+=== Current
+// <synopsis>
+// thread current ( )
+// </synopsis>
+
+Returns the currently running thread.
+Note that things such as `kill(current())` and `join(current())` are allowed, although the former merely exits and the latter hangs forever; watch out for these errors. 
+
+=== Priorities
+// <synopsis>
+// int set_priority ( thread t, int i )
+// </synopsis>
+
+// <synopsis>
+// int get_priority ( thread t )
+// </synopsis>
+
+Priorities determine how runtime is divided among threads; a thread with higher priority will always run before one with a lower priority. ``set_priority`` sets the priority of `t` to `i` and returns the new priority. ``get_priority`` returns the priority of thread ``t``. 
+
+== Mutual exclusion
+
+Consider the following situation: 
+
+----
+
+import Thread;
+
+void function para() {
+        printf("My next statement will be false.\n");
+}
+
+void function dox() {
+        printf("My previous statement was true.\n");
+}
+
+thread t = fork para();
+thread s = fork dox();
+join(t);
+join(s);
+----
+
+When run, this prints out the less than clear message 
+
+----
+
+MMyy  nperxetv isotuast esmteantte mweinltl  wbaes  ftarlusee..
+----
+
+Why? Because the two threads are running simultaneously and take turns printing out their messages; the result is that they are interleaved unreadably.
+The solution is in the builtin namespace Mutex.
+A mutex is a first-class object which threads can use to coordinate conflicting sections of code.
+Mutex defines the following functions: 
+
+=== New
+// <synopsis>
+// mutex new ( )
+// </synopsis>
+
+Creates a new mutex and returns it. 
+
+=== Acquire
+// <synopsis>
+// bool acquire ( mutex m )
+// </synopsis>
+
+`acquire` blocks until `m` is free, then locks it and returns true.
+At the top of the conflicting code, each thread should acquire the mutex; since only one at a time can have it, they will take turns executing.
+There is also a `try_acquire` that returns false immediately rather than blocking if `m` is in use, but it is deprecated. 
+
+=== Release
+// <synopsis>
+// void release ( mutex m )
+// </synopsis>
+
+When the thread which owns a mutex leaves the conflicting section of code, it should call release to free it for the next thread to acquire it. 
+
+=== Owner
+// <synopsis>
+// mutex_owner owner ( mutex m )
+// </synopsis>
+
+Returns the owner of ``m``: either the thread which currently owns it or null if it is free. 
+
+== An example
+
+This is how the example above might work with mutual exclusion: 
+
+----
+
+import Mutex;
+import Thread;
+
+mutex m = new();
+
+void function para() {
+        acquire(m);
+        printf("My next statement will be false.\n");
+        release(m);
+}
+
+void function dox() {
+        acquire(m);
+        printf("My previous statement was true.\n");
+        release(m);
+}
+
+thread t = fork para();
+thread s = fork dox();
+join(t);
+        join(s);
+----
+
+This prints out, as expected, 
+
+----
+
+My next statement will be false.
+My previous statement was true.
+----
+
+== Semaphores
+
+Nickle also has counting semaphores, implemented in the Semaphore namespace.
+Semaphores are similar to mutexes, but have some number of threads that may run that isn't necessarily one, as it is with mutexes.
+A semaphore with a count of one behaves just like a mutex. 
+
+=== New
+
+Semaphores are created with ``new``, which is unlike `Mutex::new` in that it takes an argument: the number of threads it will run simultaneously. 
+// <synopsis>
+// semaphore new ( int c )
+// </synopsis>
+
+
+=== Wait and Signal
+
+Just as Mutexes are ``acquire``d and ``release``d, threads `wait` on semaphores and `signal` them when finished. 
+// <synopsis>
+// void wait ( semaphore s )
+// </synopsis>
+
+// <synopsis>
+// void signal ( semaphore s )
+// </synopsis>
+
+`wait` merely decrements the count of ``s``, which starts with the initial value specified by ``new``.
+If the count, after the decrement, is positive, the thread continues to run; if it is negative, it blocks until the count becomes positive again.
+This will occur when one of the running threads calls ``signal``, which increments the count of `s` and wakes up another thread if any are waiting. 
+
+=== Negative initial counts
+
+If `new` is called with a negative initial count, much of the meaning of the semaphore is inverted.
+The count now refers to the number of threads that must wait until one can execute; that is, the first `c` threads will block, and the ``c``+1th will execute. 
+
+=== Why semaphores?
+
+Semaphores are useful in situations where several threads can run simultaneously, but not more than a certain number.
+They would be great, for instance, to work in a licensing system, where each thread needs some command, but only a certain number may run at a given time. 
+
+=== Be careful
+
+Semaphores, unlike mutexes, are very error-prone.
+They are not ``owned``, in the sense that mutexes are, and therefore do not check what threads are signalling or waiting on them.
+Thus, situations like this are possible: 
+
+----
+
+> import Semaphore;
+> semaphore s = new(3);
+> s  
+semaphore 1 (3);
+> wait(s);       
+> s
+semaphore 1 (2);
+> wait(s);
+> s
+semaphore 1 (1);
+> s
+semaphore 1 (1)
+> for(int i=0; i  100; ++i)
++   signal(s);
+> s
+semaphore 1 (101)
+> wait(s)
+> s
+semaphore 1 (100)
+>
+----
+
+Therefore, code must be written carefully so that threads do not signal the semaphore more than once, and only once they have waited on it. 
\ No newline at end of file
diff --git a/doc/tutorial/advanced/concurrency.sgml b/doc/tutorial/advanced/concurrency.sgml
deleted file mode 100644
index 8d4bcbc..0000000
--- a/doc/tutorial/advanced/concurrency.sgml
+++ /dev/null
@@ -1,277 +0,0 @@
-<sect1><title>Threads and Mutual Exclusion in Nickle</title>
-
-<sect2><title>Basic threading</title>
-<para>
-Threads provide concurrent processing of calculations.
-They are created with the <literal>fork</literal> operator, which spawns a child thread to evaluate its argument and returns it as a variable of the first-class type <literal>thread</literal>:
-</para>
-<synopsis>
-fork <literal>expr</literal>
-</synopsis>
-<para>
-The thread it returns is typically stored like this:
-<informalexample><screen>
-thread t = fork x!;
-</screen></informalexample>
-</para>
-<para>
-In the above example, <literal>fork</literal> immediately returns a thread, which is stored in <literal>t</literal>.
-That thread will calculate the factorial of <literal>x</literal> in the background while the program continues; when the calculation is finished it will block and wait for the parent thread (the one that forked it) to kill, join, or otherwise recognize it.
-</para>
-<para>
-<emphasis>Threads share names</emphasis>; if a thread changes the value of a variable, that change will occur in the other threads as well.
-See Mutual exclusion below.
-</para>
-</sect2>
-
-<sect2><title>Thread functions</title>
-<para>
-The builtin namespace Thread has functions for manipulating threads once they have been forked.
-</para>
-
-<sect3><title>Kill</title>
-<synopsis>
-int kill ( thread t, ... )
-</synopsis>
-<para>
-Kills the threads it takes as arguments, regardless of whether or not they are finished, and returns the number of threads successfully killed. 
-</para>
-</sect3>
-
-<sect3><title>Join</title>
-<synopsis>
-poly join ( thread t )
-</synopsis>
-<para>
-Waits for thread <literal>t</literal> to finish and returns the value of its expression.
-This is how to get the value back out of a thread.
-Once joined, the thread will dissappear.
-For example,
-<informalexample><screen>
-thread t = fork 1000!;
-# something else...
-printf("1000! = %d\n",Thread::join(t));
-</screen></informalexample>
-</para>
-<para>
-will execute 'something else' while <literal>t</literal> runs, then wait for it to complete and print out its value.
-</para>
-</sect3>
-
-<sect3><title>Current</title>
-<synopsis>
-thread current ( )
-</synopsis>
-<para>
-Returns the currently running thread. Note that things such as <literal>kill(current())</literal> and <literal>join(current())</literal> are allowed, although the former merely exits and the latter hangs forever; watch out for these errors.
-</para>
-</sect3>
-
-<sect3><title>Priorities</title>
-<synopsis>
-int set_priority ( thread t, int i )
-</synopsis>
-<synopsis>
-int get_priority ( thread t )
-</synopsis>
-<para>
-Priorities determine how runtime is divided among threads; a thread with higher priority will always run before one with a lower priority.
-<literal>set_priority</literal> sets the priority of <literal>t</literal> to <literal>i</literal> and returns the new priority.
-<literal>get_priority</literal> returns the priority of thread <literal>t</literal>.
-</para>
-</sect3>
-
-</sect2>
-
-<sect2><title>Mutual exclusion</title>
-<para>
-Consider the following situation:
-<informalexample><screen>
-import Thread;
-
-void function para() {
-        printf("My next statement will be false.\n");
-}
-
-void function dox() {
-        printf("My previous statement was true.\n");
-}
-
-thread t = fork para();
-thread s = fork dox();
-join(t);
-join(s);
-</screen></informalexample>
-</para>
-<para>
-When run, this prints out the less than clear message
-<informalexample><screen>
-MMyy  nperxetv isotuast esmteantte mweinltl  wbaes  ftarlusee..
-</screen></informalexample>
-</para>
-<para>
-Why? Because the two threads are running simultaneously and take turns printing out their messages; the result is that they are interleaved unreadably.
-The solution is in the builtin namespace Mutex.
-A mutex is a first-class object which threads can use to coordinate conflicting sections of code.
-Mutex defines the following functions:
-</para>
-
-<sect3><title>New</title>
-<synopsis>
-mutex new ( )
-</synopsis>
-<para>
-Creates a new mutex and returns it.
-</para>
-</sect3>
-
-<sect3><title>Acquire</title>
-<synopsis>
-bool acquire ( mutex m )
-</synopsis>
-<para>
-<literal>acquire</literal> blocks until <literal>m</literal> is free, then locks it and returns true.
-At the top of the conflicting code, each thread should acquire the mutex; since only one at a time can have it, they will take turns executing.
-There is also a <literal>try_acquire</literal> that returns false immediately rather than blocking if <literal>m</literal> is in use, but it is deprecated.
-</para>
-</sect3>
-
-<sect3><title>Release</title>
-<synopsis>
-void release ( mutex m )
-</synopsis>
-<para>
-When the thread which owns a mutex leaves the conflicting section of code, it should call release to free it for the next thread to acquire it.
-</para>
-</sect3>
-
-<sect3><title>Owner</title>
-<synopsis>
-mutex_owner owner ( mutex m )
-</synopsis>
-<para>
-Returns the owner of <literal>m</literal>: either the thread which currently owns it or null if it is free.
-</para>
-</sect3>
-
-</sect2>
-
-<sect2><title>An example</title>
-<para>
-This is how the example above might work with mutual exclusion:
-<informalexample><screen>
-import Mutex;
-import Thread;
-
-mutex m = new();
-
-void function para() {
-        acquire(m);
-        printf("My next statement will be false.\n");
-        release(m);
-}
-
-void function dox() {
-        acquire(m);
-        printf("My previous statement was true.\n");
-        release(m);
-}
-
-thread t = fork para();
-thread s = fork dox();
-join(t);
-        join(s);
-</screen></informalexample>
-</para>
-<para>
-This prints out, as expected,
-<informalexample><screen>
-My next statement will be false.
-My previous statement was true.
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Semaphores</title>
-<para>
-Nickle also has counting semaphores, implemented in the Semaphore namespace.
-Semaphores are similar to mutexes, but have some number of threads that may run that isn't necessarily one, as it is with mutexes.
-A semaphore with a count of one behaves just like a mutex.
-</para>
-
-<sect3><title>New</title>
-<para>
-Semaphores are created with <literal>new</literal>, which is unlike <literal>Mutex::new</literal> in that it takes an argument: the number of threads it will run simultaneously.
-</para>
-<synopsis>
-semaphore new ( int c )
-</synopsis>
-</sect3>
-
-<sect3><title>Wait and Signal</title>
-<para>
-Just as Mutexes are <literal>acquire</literal>d and <literal>release</literal>d, threads <literal>wait</literal> on semaphores and <literal>signal</literal> them when finished.
-</para>
-<synopsis>
-void wait ( semaphore s )
-</synopsis>
-<synopsis>
-void signal ( semaphore s )
-</synopsis>
-<para>
-<literal>wait</literal> merely decrements the count of <literal>s</literal>, which starts with the initial value specified by <literal>new</literal>.
-If the count, after the decrement, is positive, the thread continues to run; if it is negative, it blocks until the count becomes positive again.
-This will occur when one of the running threads calls <literal>signal</literal>, which increments the count of <literal>s</literal> and wakes up another thread if any are waiting.
-</para>
-</sect3>
-
-<sect3><title>Negative initial counts</title>
-<para>
-If <literal>new</literal> is called with a negative initial count, much of the meaning of the semaphore is inverted.
-The count now refers to the number of threads that must wait until one can execute; that is, the first <literal>c</literal> threads will block, and the <literal>c</literal>+1th will execute.
-</para>
-</sect3>
-
-<sect3><title>Why semaphores?</title>
-<para>
-Semaphores are useful in situations where several threads can run simultaneously, but not more than a certain number.
-They would be great, for instance, to work in a licensing system, where each thread needs some command, but only a certain number may run at a given time.
-</para>
-</sect3>
-
-<sect3><title>Be careful</title>
-<para>
-Semaphores, unlike mutexes, are very error-prone.
-They are not <literal>owned</literal>, in the sense that mutexes are, and therefore do not check what threads are signalling or waiting on them.
-Thus, situations like this are possible:
-<informalexample><screen>
-> import Semaphore;
-> semaphore s = new(3);
-> s  
-semaphore 1 (3);
-> wait(s);       
-> s
-semaphore 1 (2);
-> wait(s);
-> s
-semaphore 1 (1);
-> s
-semaphore 1 (1)
-> for(int i=0; i < 100; ++i)
-+   signal(s);
-> s
-semaphore 1 (101)
-> wait(s)
-> s
-semaphore 1 (100)
-> 
-</screen></informalexample>
-</para>
-<para>
-Therefore, code must be written carefully so that threads do not signal the semaphore more than once, and only once they have waited on it.
-</para>
-</sect3>
-
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/advanced/continuations.sgml b/doc/tutorial/advanced/continuations.adoc
similarity index 68%
rename from doc/tutorial/advanced/continuations.sgml
rename to doc/tutorial/advanced/continuations.adoc
index 7c4b153..bcf5f38 100644
--- a/doc/tutorial/advanced/continuations.sgml
+++ b/doc/tutorial/advanced/continuations.adoc
@@ -1,25 +1,26 @@
-<sect1><title>Nickle Continuations</title>
-<para>
-Arbitrary flow control is accomplished in Nickle with first-class continuations and the functions <literal>setjmp</literal> and <literal>longjmp</literal>.
-These are similar to those in C, but without restrictions on the target.
-</para>
-<synopsis>
-poly setjmp ( continuation *c, poly retval )
-</synopsis>
-<synopsis>
-void lomgjmp ( continuation c, poly retval )
-</synopsis>
-<para>
-Setjmp saves the state of the program, including program counter and names in scope, in <literal>c</literal> and returns <literal>retval</literal>.
-</para>
-<para>
-Longjmp returns <literal>retval</literal> <emphasis>from the setjmp that set <literal>c</literal></emphasis>.
-There can be two distinctions from this jump and the initial call to setjmp: the return value may differ, and variables that have changed retain their new values.
-</para>
-<para>
+
+= Nickle Continuations
+
+Arbitrary flow control is accomplished in Nickle with first-class continuations and the functions `setjmp` and ``longjmp``.
+These are similar to those in C, but without restrictions on the target. 
+// <synopsis>
+// poly setjmp ( continuation *c, poly retval )
+// </synopsis>
+
+// <synopsis>
+// void lomgjmp ( continuation c, poly retval )
+// </synopsis>
+
+Setjmp saves the state of the program, including program counter and names in scope, in `c` and returns ``retval``. 
+
+Longjmp returns `retval`__from the setjmp that set ``__c__``__.
+There can be two distinctions from this jump and the initial call to setjmp: the return value may differ, and variables that have changed retain their new values. 
+
 Continuations are often used to implement control structures that do not exist in the language, interpreters, and escaping from recursive algorithms.
-For example, the following is a simple binary tree search that uses continuations to jump directly to the top instead of returning up each branch once the result is found.
-<informalexample><screen><![CDATA[
+For example, the following is a simple binary tree search that uses continuations to jump directly to the top instead of returning up each branch once the result is found. 
+
+----
+
 typedef tree;
 
 typedef struct {
@@ -51,22 +52,17 @@ int i = 0;
         else
                 printf ( "value = %g\n", p );
 }
-]]></screen></informalexample>
-</para>
-<para>
-This is a pretty normal binary tree search, but notice how it is run: a continuation is set; if setjmp returns <> (which it will the first time), a value is searched for (this is a pretty degenerate example with only one node).
-If an actual value is returned, it must be from the longjmp in search, and the value is printed; a message is printed to emphasize that setjmp returns twice.
-This optimizes the return from what can be a very deeply nested search.
-</para>
-<para>
+
+----
+
+This is a pretty normal binary tree search, but notice how it is run: a continuation is set; if setjmp returns <> (which it will the first time), a value is searched for (this is a pretty degenerate example with only one node). If an actual value is returned, it must be from the longjmp in search, and the value is printed; a message is printed to emphasize that setjmp returns twice.
+This optimizes the return from what can be a very deeply nested search. 
+
 Notice that the last part of the code is inside curly braces.
 This is legal, of course, but ordinarily not very useful.
 It is used in this case to get around a slight flaw in Nickle: currently, each top-level command is executed in its own thread.
 Thus when longjmp tries to return from the setjmp, that thread has already finished and the program exits.
-By placing those statements in curly braces, they will all be executed in the same thread and setjmp will still exist for longjmp to find.
-</para>
-<para>
+By placing those statements in curly braces, they will all be executed in the same thread and setjmp will still exist for longjmp to find. 
+
 This sort of escape from a nested search is also commonly done with exceptions, raising one when the value is found and catching it at the top, passing the value as an argument to the exception.
 Actually, that method is more common because of its simplicity, but this example was done using continuations to demonstrate them.
-</para>
-</sect1>
diff --git a/doc/tutorial/advanced/copying.sgml b/doc/tutorial/advanced/copying.adoc
similarity index 50%
rename from doc/tutorial/advanced/copying.sgml
rename to doc/tutorial/advanced/copying.adoc
index 0a23690..d970d91 100644
--- a/doc/tutorial/advanced/copying.sgml
+++ b/doc/tutorial/advanced/copying.adoc
@@ -1,86 +1,85 @@
-<sect1><title>Copy Semantics and Garbage Collection</title>
 
-<sect2><title>Copy by value</title>
-<para>
+= Copy Semantics and Garbage Collection
+
+== Copy by value
+
 In Nickle, assignment, argument passing, and definitions--in short everything involving the values of variables--are all by-value.
 Nickle avoids the weird C-isms, like being by-value except for arrays and strings.
 Everything is copied.
-Consider the following example:
-<informalexample><screen>
+Consider the following example: 
+
+----
+
 > int[*] foo = { 1, 2, 3 };
 > int[*] bar = foo;
 > foo[2] = 4;
 > foo
 [3] {1, 2, 4}
-</screen></informalexample>
-</para>
-<para>
-What will <literal>bar[2]</literal> be?
-<informalexample><screen>
+----
+
+What will `bar[2]` be? 
+
+----
+
 > bar
 [3] {1, 2, 3}
-</screen></informalexample>
-</para>
-<para>
+----
+
 Since assignment is by-value, bar has its own values--it is unchanged.
-Also consider function arguments:
-<informalexample><screen>
+Also consider function arguments: 
+
+----
+
 > string s = "hello, world"; 
 > (void func(string s) { s = "foobar"; printf("%s\n",s); })(s);
 foobar
-</screen></informalexample>
-</para>
-<para>
-Does <literal>s</literal> still have its original value, or "foobar"?
-Since the function was modifying a copy--which was passed by-value--<literal>s</literal> will be unchanged.
-<informalexample><screen>
+----
+
+Does `s` still have its original value, or "foobar"? Since the function was modifying a copy--which was passed by-value--``s`` will be unchanged. 
+
+----
+
 > s
 "hello, world"
-</screen></informalexample>
-</para>
-<para>
-What if you want to pass something by reference?
-Nickle has a reference type to accomplish just that.
+----
+
+What if you want to pass something by reference? Nickle has a reference type to accomplish just that.
 (You could also use pointers, but references are The Right Way.
-Anyway, pointers may eventually be removed from the language in preference to references.)
-For example, to reimplement the example above using references:
-<informalexample><screen><![CDATA[
+Anyway, pointers may eventually be removed from the language in preference to references.) For example, to reimplement the example above using references: 
+
+----
+
 > string s = "hello, world";
 > (void func(&string s) { s = "foobar"; printf("%s\n",s); })(&s);
 foobar
 > s
 "foobar"
-]]></screen></informalexample>
-</para>
-<para>
-Notice that <literal>s</literal> was changed; it was passed as a reference (&string).
-See the section on Variables for a discussion of references.
-</para>
-</sect2>
-
-<sect2><title>Garbage collection</title>
-<para>
-But if all those strings and arrays are copied entirely every time a function is called or an assignment made, won't there be a lot of unused, unreferenceable memory lying around?
-No. Nickle is fully garbage-collected; when a value no longer has any names, it is freed.
-This is invisible to the user/programmer, who need not worry about allocation, deallocation, or any other aspects of their assignments and argument passing.
-</para>
-<para>
-In short, everything is by-value, and Nickle takes care of allocation and deallocation.
-</para>
-</sect2>
-
-<sect2><title>Type checking and subtyping</title>
-<para>
+----
+
+Notice that `s` was changed; it was passed as a reference (&string). See the section on Variables for a discussion of references. 
+
+== Garbage collection
+
+But if all those strings and arrays are copied entirely every time a function is called or an assignment made, won't there be a lot of unused, unreferenceable memory lying around? No.
+Nickle is fully garbage-collected; when a value no longer has any names, it is freed.
+This is invisible to the user/programmer, who need not worry about allocation, deallocation, or any other aspects of their assignments and argument passing. 
+
+In short, everything is by-value, and Nickle takes care of allocation and deallocation. 
+
+== Type checking and subtyping
+
 Type checking in Nickle is a combination of compile-time and runtime checking.
 At compile-time, Nickle will ensure that all assignments, argument passing, and other copying situations are sane, for instance that no strings are being assigned to integers.
 It will let some errors through if it cannot be sure they are errors.
-For instance, variables of type 'poly' can hold any type; at compile-time, nothing is ruled out, but this does not mean you can't break typing at run-time.
-</para>
-<para>
+For instance, variables of type 'poly' can hold any type; at compile-time, nothing is ruled out, but this does not mean you can't break typing at run-time. 
+
 At runtime, Nickle makes sure all assignments are actually valid.
-It does so by determining if one type is a subtype of the other, i.e. if the set of all values that can fit in it also fit into the other.
-As a concrete example:
-<informalexample><screen><![CDATA[
+It does so by determining if one type is a subtype of the other, i.e.
+if the set of all values that can fit in it also fit into the other.
+As a concrete example: 
+
+----
+
 > int i = 1;
 > rational r = i;
 > i = r/3;
@@ -88,21 +87,20 @@ Unhandled exception "invalid_argument" at <stdin>:8
         (1/3)
         0
         "Incompatible types in assignment"
-]]></screen></informalexample>
-</para>
-<para>
+----
+
 The int can hold the integer value 1 without difficulty, because they are the same type.
 The rational can accept the same value because integers are a subset of rationals.
 However, attempting to assign a rational (1/3) to the integer raises an exception.
 This demonstrates that int is a subtype of rational; conversely, rational is the supertype of int.
-A variable can take on a value from any of its subtypes, but not from its supertypes--and if the two values do not share a sub/supertype relationship, they will not get pass the compile-time
-checker.
-</para>
-<para>
+A variable can take on a value from any of its subtypes, but not from its supertypes--and if the two values do not share a sub/supertype relationship, they will not get pass the compile-time checker. 
+
 A similar check occurs with structs.
 If one struct's elements are a subset of another's, it may take that value.
-For example,
-<informalexample><screen><![CDATA[
+For example, 
+
+----
+
 > typedef struct { int i; string s; } i_and_s;
 > typedef struct { int i; } just_i;
 > i_and_s is = { i=2, s="hello" };
@@ -113,25 +111,12 @@ Unhandled exception "invalid_argument" at <stdin>:17
         {i = 2}
         0
         "Incompatible types in assignment"
-]]></screen></informalexample>
-</para>
-<para>
-Since <literal>just_i</literal> is a subtype of <literal>i_and_s</literal> (it has <literal>i</literal> but not <literal>s</literal>), the assignment to <literal>i</literal> from <literal>is</literal> worked.
-However, attempting to assign to <literal>is</literal> from a <literal>just_i</literal> failed, because it did not have an <literal>s</literal> to copy over.
-</para>
-<para>
-Finally, in assignments of one function to another, the following must be the case:
-</para>
-<itemizedlist>
-<listitem><para>
-The arguments of the right-side function must be able to be assigned to those of the left-side function.
-In other words, that on the left must accept a subset of the arguments of that on the right.
-</para></listitem>
-<listitem><para>
-The return type of the left-side function must be able to be assigned to that of the right-side function.
-In other words, its value should be usable anywhere that of the one on the right could be used.
-</para></listitem>
-</itemizedlist>
-</sect2>
-
-</sect1>
+----
+
+Since `just_i` is a subtype of `i_and_s` (it has `i` but not ``s``), the assignment to `i` from `is` worked.
+However, attempting to assign to `is` from a `just_i` failed, because it did not have an `s` to copy over. 
+
+Finally, in assignments of one function to another, the following must be the case: 
+
+* The arguments of the right-side function must be able to be assigned to those of the left-side function. In other words, that on the left must accept a subset of the arguments of that on the right. 
+* The return type of the left-side function must be able to be assigned to that of the right-side function. In other words, its value should be usable anywhere that of the one on the right could be used. 
diff --git a/doc/tutorial/advanced/exceptions.adoc b/doc/tutorial/advanced/exceptions.adoc
new file mode 100644
index 0000000..4ec17e0
--- /dev/null
+++ b/doc/tutorial/advanced/exceptions.adoc
@@ -0,0 +1,110 @@
+
+= Nickle Exceptions
+
+Nickle has first-class exceptions for error handling and quick escapes from recursive algorithms.
+A number of exceptions are builtin to Nickle that it throws for various errors, including: 
+
+* exception uninitialized_value(string msg) - Attempt to use an uninitialized value.
+* exception invalid_argument(string msg,int arg,poly val) - The ``arg``th argument to a builtin function had invalid value ``val``.
+* exception readonly_box(string msg,poly val) - Attempt to change the value of a read-only quantity to ``val``.
+* exception invalid_array_bounds(string msg,poly a,poly i) - Attempt to access array `a` at index `i` is out of bounds.
+* exception divide_by_zero(string msg,real num,real den) - Attempt to divide `num` by `den` when `den` is zero.
+* exception invalid_struct_member(string msg,poly struct,string name) - Attempt to refer to member `name` of the object ``struct``, which does not exist.
+* exception invalid_binop_values(string msg,poly arg1,poly arg2) - Attempt to evaluate a binary operator with arguments `arg1` and ``arg2``, where at least one of these values is invalid.
+* exception invalid_unop_values(string msg,poly arg) - Attempt to evaluate a unary operator with invalid argument ``arg``.
+
+The following syntax may be used to declare a new exception: 
+// <synopsis>
+// exception <replaceable>name</replaceable> ( <replaceable>type</replaceable> <replaceable>name</replaceable>, ... )
+// </synopsis>
+
+For example, 
+
+----
+
+exception my_exception ( string msg, int a, int b, int c );
+----
+
+== Raise
+// <synopsis>
+// raise <replaceable>name</replaceable> ( <replaceable>value</replaceable>, ... )
+// </synopsis>
+
+Raises the named exception with the given arguments, e.g. 
+
+----
+
+raise my_exception ( "message", 0, 1, 2 );
+----
+
+Execution is broken and `my_exception` travels up the stack until it is caught by a try-catch block or it reaches the top level, where it prints an error message such as: 
+
+----
+
+Unhandled exception "my_exception"
+        3
+        2
+        1
+        "message"
+----
+
+== Try - catch
+// <synopsis>
+// try <replaceable>statement</replaceable>
+// </synopsis>
+
+// <synopsis>
+// catch <replaceable>name</replaceable> ( <replaceable>type</replaceable> <replaceable>name</replaceable>, ... ) { <replaceable>statement-list</replaceable> }
+// </synopsis>
+
+`try` executes [replaceable]``statement``; if it raises an exception whose name matches that of a succeeding `catch` block, the arguments are placed in the names specified and the associated [replaceable]``statement-list`` is executed.
+Control continues after the catch without continuing up the stack; if further propagation is desired, [replaceable]``statement-list`` should re-raise the exception.
+Any number of catch blocks may be associated with a try statement.
+For example: 
+
+----
+
+exception my_exception(string msg,int a,int b,int c);
+
+try raise my_exception("blah",1,2,3);
+catch my_exception(string msg,int a,int b,int c) {
+        printf("%s: exception successfully caught (%d,%d,%d).\n",msg,a,b,c);
+}
+----
+
+This example tries to execute a function that raises an exception; since that exception matches the catch block, "blah", 1, 2, and 3 (the arguments) are put into ``msg``, ``a``, ``b``, and `c` and the statement list is executed, which in this case merely prints out the arguments received and continues: 
+
+----
+
+blah: exception successfully caught (1,2,3).
+----
+
+== Twixt
+
+Nickle does not provide a `finally` clause to a ``try-catch``.
+In order to ensure the order of some expressions, it provides `twixt` (See the section on Statements). For example, 
+
+----
+
+exception my_exception(string msg, int a, int b, int c);
+
+void foo(string msg, int a, int b, int c) {
+        twixt(printf("entering twixt..."); printf("leaving twixt.\n"))
+                raise my_exception(msg, a, b, c);
+}
+
+try foo("blah", 1, 2, 3);
+catch my_exception(string msg,int a,int b,int c) {
+printf("%s: exception successfully caught (%d,%d,%d).\n",msg,a,b,c);
+}
+----
+Will produce the output: 
+
+----
+
+entering twixt...leaving twixt.
+blah: exception successfully caught (1,2,3).
+----
+
+Notice the order of the printed messages: `twixt` finished up before the exception was handled by the ``catch``.
+This is an elegant way to accomplish something that should be done finally, in this case printing the message "leaving twixt" for demonstration. 
\ No newline at end of file
diff --git a/doc/tutorial/advanced/exceptions.sgml b/doc/tutorial/advanced/exceptions.sgml
deleted file mode 100644
index 892f8a1..0000000
--- a/doc/tutorial/advanced/exceptions.sgml
+++ /dev/null
@@ -1,110 +0,0 @@
-<sect1><title>Nickle Exceptions</title>
-<para>
-Nickle has first-class exceptions for error handling and quick escapes from recursive algorithms.
-A number of exceptions are builtin to Nickle that it throws for various errors, including:
-</para>
-<itemizedlist>
-<listitem><para>exception uninitialized_value(string msg) - Attempt to use an uninitialized value.</para></listitem>
-<listitem><para>exception invalid_argument(string msg,int arg,poly val) - The <literal>arg</literal>th argument to a builtin function had invalid value <literal>val</literal>.</para></listitem>
-<listitem><para>exception readonly_box(string msg,poly val) - Attempt to change the value of a read-only quantity to <literal>val</literal>.</para></listitem>
-<listitem><para>exception invalid_array_bounds(string msg,poly a,poly i) - Attempt to access array <literal>a</literal> at index <literal>i</literal> is out of bounds.</para></listitem>
-<listitem><para>exception divide_by_zero(string msg,real num,real den) - Attempt to divide <literal>num</literal> by <literal>den</literal> when <literal>den</literal> is zero.</para></listitem>
-<listitem><para>exception invalid_struct_member(string msg,poly struct,string name) - Attempt to refer to member <literal>name</literal> of the object <literal>struct</literal>, which does not exist.</para></listitem>
-<listitem><para>exception invalid_binop_values(string msg,poly arg1,poly arg2) - Attempt to evaluate a binary operator with arguments <literal>arg1</literal> and <literal>arg2</literal>, where at least one of these values is invalid.</para></listitem>
-<listitem><para>exception invalid_unop_values(string msg,poly arg) - Attempt to evaluate a unary operator with invalid argument <literal>arg</literal>.</para></listitem>
-</itemizedlist>
-<para>
-The following syntax may be used to declare a new exception:
-</para>
-<synopsis>
-exception <replaceable>name</replaceable> ( <replaceable>type</replaceable> <replaceable>name</replaceable>, ... )
-</synopsis>
-<para>
-For example,
-<informalexample><screen>
-exception my_exception ( string msg, int a, int b, int c );
-</screen></informalexample>
-</para>
-
-<sect2><title>Raise</title>
-<synopsis>
-raise <replaceable>name</replaceable> ( <replaceable>value</replaceable>, ... )
-</synopsis>
-<para>
-Raises the named exception with the given arguments, e.g.
-<informalexample><screen>
-raise my_exception ( "message", 0, 1, 2 );
-</screen></informalexample>
-</para>
-<para>
-Execution is broken and <literal>my_exception</literal> travels up the stack until it is caught by a try-catch block or it reaches the top level, where it prints an error message such as:
-<informalexample><screen>
-Unhandled exception "my_exception"
-        3
-        2
-        1
-        "message"
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Try - catch</title>
-<synopsis>
-try <replaceable>statement</replaceable>
-</synopsis>
-<synopsis>
-catch <replaceable>name</replaceable> ( <replaceable>type</replaceable> <replaceable>name</replaceable>, ... ) { <replaceable>statement-list</replaceable> }
-</synopsis>
-<para>
-<literal>try</literal> executes <replaceable>statement</replaceable>; if it raises an exception whose name matches that of a succeeding <literal>catch</literal> block, the arguments are placed in the names specified and the associated <replaceable>statement-list</replaceable> is executed.
-Control continues after the catch without continuing up the stack; if further propagation is desired, <replaceable>statement-list</replaceable> should re-raise the exception.
-Any number of catch blocks may be associated with a try statement.
-For example:
-<informalexample><screen>
-exception my_exception(string msg,int a,int b,int c);
-
-try raise my_exception("blah",1,2,3);
-catch my_exception(string msg,int a,int b,int c) {
-        printf("%s: exception successfully caught (%d,%d,%d).\n",msg,a,b,c);
-}
-</screen></informalexample>
-</para>
-<para>
-This example tries to execute a function that raises an exception; since that exception matches the catch block, "blah", 1, 2, and 3 (the arguments) are put into <literal>msg</literal>, <literal>a</literal>, <literal>b</literal>, and <literal>c</literal> and the statement list is executed, which in this case merely prints out the arguments received and continues:
-<informalexample><screen>
-blah: exception successfully caught (1,2,3).
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Twixt</title>
-<para>
-Nickle does not provide a <literal>finally</literal> clause to a <literal>try-catch</literal>.
-In order to ensure the order of some expressions, it provides <literal>twixt</literal> (See the section on Statements).
-For example,
-<informalexample><screen>
-exception my_exception(string msg, int a, int b, int c);
-
-void foo(string msg, int a, int b, int c) {
-        twixt(printf("entering twixt..."); printf("leaving twixt.\n"))
-                raise my_exception(msg, a, b, c);
-}
-
-try foo("blah", 1, 2, 3);
-catch my_exception(string msg,int a,int b,int c) {
-printf("%s: exception successfully caught (%d,%d,%d).\n",msg,a,b,c);
-}
-</screen></informalexample>
-Will produce the output:
-<informalexample><screen>
-entering twixt...leaving twixt.
-blah: exception successfully caught (1,2,3).
-</screen></informalexample>
-</para>
-<para>
-Notice the order of the printed messages: <literal>twixt</literal> finished up before the exception was handled by the <literal>catch</literal>.
-This is an elegant way to accomplish something that should be done finally, in this case printing the message "leaving twixt" for demonstration.
-</para>
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/advanced/namespaces.adoc b/doc/tutorial/advanced/namespaces.adoc
new file mode 100644
index 0000000..7ce890f
--- /dev/null
+++ b/doc/tutorial/advanced/namespaces.adoc
@@ -0,0 +1,92 @@
+
+= Nickle Namespaces
+
+Namespaces collect related variable and function names and allow control over visibility.
+A number of Nickle builtins are gathered into builtin namespaces that may be used.
+The following builtin namespaces have sections in this tutorial: 
+
+* Math - Useful mathematical functions.
+* File - File input/output with the 'file' type.
+* Thread - Concurrent processing.
+* Semaphore and Mutex - Synchronization of threads.
+* String - Useful functions for strings.
+
+An example namespace might be declared like this: 
+
+----
+
+namespace Example {
+
+        int blah = 1;
+        public int a = 0;
+
+        int function bar(int a) {
+                ...
+        }
+        
+        protected int function foo(int a) {
+                ...
+        }
+
+}
+----
+
+The keyword `namespace` is followed by the name of the namespace and a list of statements that declare names in the namespace.
+The publication of those declarations, e.g. `public` or `protected` defines how visible they will be outside the namespace.
+The namespace itself may be preceeded by publication information, __but this has no bearing on the names within the namespace__; it defines the visibility of the name of the namespace.
+If the example above had been declared 
+
+----
+
+protected namespace Example {
+        ...
+}
+----
+Then the names within `Example` would have the same visibility as always, but `Example` itself would be protected in whatever namespace it belongs to.
+In this case, it belongs to the top-level namespace, but namespaces can be nested within each other, which makes the visibility of their own names important. 
+
+== Extend
+// <synopsis>
+// extend namespace <replaceable>name</replaceable> { <replaceable>statement-list</replaceable> }
+// </synopsis>
+
+Names may be added to a namespace after it is initially defined with the `extend` command.
+The namespace `name` is reopened and the new `statement-list` is added to the previous ones.
+For example, 
+
+----
+
+extend namespace Example {
+        string[*] greeting = [2]{ "hello", "world" };
+}
+----
+
+Adds `greeting` to the names already defined in ``Example``. 
+
+== Peering inside
+// <synopsis>
+// <replaceable>namespace</replaceable>::<replaceable>name</replaceable>
+// </synopsis>
+
+// <synopsis>
+// import <replaceable>namespace</replaceable>
+// </synopsis>
+
+The `::` operator refers to a [replaceable]``name``, which is in [replaceable]``namespace``, analogously to a structure dereference.
+If [replaceable]``name`` also refers to a namespace, its names too are visible this way.
+Either `protected` or `public` names are visible in this way. 
+
+An `import` statement brings all the public names in [replaceable]``namespace`` into scope, overshadowing conflicting names.
+Thereafter, those names may be used normally. 
+
+A variable is declared with one of three visibilities that defines how it is visible outside its namespace: 
+
+* "public" may be seen outside with `::` or imported
+* "protected" may be seen outside with `::` but not imported
+* if neither is specified, it may not be seen outside at all
+
+Thus, in our example namespace ``Example``: 
+
+* ``blah``, ``bar``, and `greeting` have no visibility specified and may only be used inside ``Example``.
+* both `a` (which is public) and `foo` (which is protected) may be seen with ``::``.
+* an `import` will only bring `a` into scope, as it is the only name that is public.
diff --git a/doc/tutorial/advanced/namespaces.sgml b/doc/tutorial/advanced/namespaces.sgml
deleted file mode 100644
index 1433583..0000000
--- a/doc/tutorial/advanced/namespaces.sgml
+++ /dev/null
@@ -1,100 +0,0 @@
-<sect1><title>Nickle Namespaces</title>
-<para>
-Namespaces collect related variable and function names and allow control over visibility.
-A number of Nickle builtins are gathered into builtin namespaces that may be used.
-The following builtin namespaces have sections in this tutorial:
-</para>
-<itemizedlist>
-<listitem><para>Math - Useful mathematical functions.</para></listitem>
-<listitem><para>File - File input/output with the 'file' type.</para></listitem>
-<listitem><para>Thread - Concurrent processing.</para></listitem>
-<listitem><para>Semaphore and Mutex - Synchronization of threads.</para></listitem>
-<listitem><para>String - Useful functions for strings.</para></listitem>
-</itemizedlist>
-<para>
-An example namespace might be declared like this:
-<informalexample><screen>
-namespace Example {
-
-        int blah = 1;
-        public int a = 0;
-
-        int function bar(int a) {
-                ...
-        }
-        
-        protected int function foo(int a) {
-                ...
-        }
-
-}
-</screen></informalexample>
-</para>
-<para>
-The keyword <literal>namespace</literal> is followed by the name of the namespace and a list of statements that declare names in the namespace.
-The publication of those declarations, e.g. <literal>public</literal> or <literal>protected</literal> defines how visible they will be outside the namespace.
-The namespace itself may be preceeded by publication information, <emphasis>but this has no bearing on the names within the namespace</emphasis>; it defines the visibility of the name of the namespace.
-If the example above had been declared
-<informalexample><screen>
-protected namespace Example {
-        ...
-}
-</screen></informalexample>
-Then the names within <literal>Example</literal> would have the same visibility as always, but <literal>Example</literal> itself would be protected in whatever namespace it belongs to.
-In this case, it belongs to the top-level namespace, but namespaces can be nested within each other, which makes the visibility of their own names important.
-</para>
-
-<sect2><title>Extend</title>
-<synopsis>
-extend namespace <replaceable>name</replaceable> { <replaceable>statement-list</replaceable> }
-</synopsis>
-<para>
-Names may be added to a namespace after it is initially defined with the <literal>extend</literal> command.
-The namespace <literal>name</literal> is reopened and the new <literal>statement-list</literal> is added to the previous ones.
-For example,
-<informalexample><screen>
-extend namespace Example {
-        string[*] greeting = [2]{ "hello", "world" };
-}
-</screen></informalexample>
-</para>
-<para>
-Adds <literal>greeting</literal> to the names already defined in <literal>Example</literal>.
-</para>
-</sect2>
-
-<sect2><title>Peering inside</title>
-<synopsis>
-<replaceable>namespace</replaceable>::<replaceable>name</replaceable>
-</synopsis>
-<synopsis>
-import <replaceable>namespace</replaceable>
-</synopsis>
-<para>
-The <literal>::</literal> operator refers to a <replaceable>name</replaceable>, which is in <replaceable>namespace</replaceable>, analogously to a structure dereference.
-If <replaceable>name</replaceable> also refers to a namespace, its names too are visible this way.
-Either <literal>protected</literal> or <literal>public</literal> names are visible in this way.
-</para>
-<para>
-An <literal>import</literal> statement brings all the public names in <replaceable>namespace</replaceable> into scope, overshadowing conflicting names.
-Thereafter, those names may be used normally.
-</para>
-<para>
-A variable is declared with one of three visibilities that defines how it is visible outside its namespace:
-</para>
-<itemizedlist>
-<listitem><para>"public" may be seen outside with <literal>::</literal> or imported</para></listitem>
-<listitem><para>"protected" may be seen outside with <literal>::</literal> but not imported</para></listitem>
-<listitem><para>if neither is specified, it may not be seen outside at all</para></listitem>
-</itemizedlist>
-<para>
-Thus, in our example namespace <literal>Example</literal>:
-</para>
-<itemizedlist>
-<listitem><para><literal>blah</literal>, <literal>bar</literal>, and <literal>greeting</literal> have no visibility specified and may only be used inside <literal>Example</literal>.</para></listitem>
-<listitem><para>both <literal>a</literal> (which is public) and <literal>foo</literal> (which is protected) may be seen with <literal>::</literal>.</para></listitem>
-<listitem><para>an <literal>import</literal> will only bring <literal>a</literal> into scope, as it is the only name that is public.</para></listitem>
-</itemizedlist>
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/basics/command.sgml b/doc/tutorial/basics/command.adoc
similarity index 51%
rename from doc/tutorial/basics/command.sgml
rename to doc/tutorial/basics/command.adoc
index 7aef489..54da0be 100644
--- a/doc/tutorial/basics/command.sgml
+++ b/doc/tutorial/basics/command.adoc
@@ -1,14 +1,16 @@
-<sect1><title>Commands</title>
-<para>
+
+= Commands
+
 The following are commands that the Nickle interpreter understands, not actual language constructs.
-They may be issued only at the top level.
-</para>
-
-<sect2><title>Expressions</title>
-<para>
-If an expression is issued at the top level, such as <literal>3**4</literal> or <literal>100!,</literal>, its value is printed to standard output.
-If the expression ends with a # sign and another expression, its value is printed in whatever base the second expression evaluates to.
-<informalexample><screen>
+They may be issued only at the top level. 
+
+== Expressions
+
+If an expression is issued at the top level, such as `3**4` or ``100!,``, its value is printed to standard output.
+If the expression ends with a # sign and another expression, its value is printed in whatever base the second expression evaluates to. 
+
+----
+
 $ nickle
 > 10!
 3628800
@@ -17,39 +19,41 @@ $ nickle
 > 3**4 # 3
 10000
 >
-</screen></informalexample>
-</para>
-<para>
+----
+
 Statements, from expressions terminated by semicolons to complicated control structures, are executed but have no value to print.
 Statements are not commands but actual syntax, so they may be used in scripts.
-If a line is ended before it can be sensible as an expression or statement, Nickle will continue until it is a statement, e.g.
-<informalexample><screen>
+If a line is ended before it can be sensible as an expression or statement, Nickle will continue until it is a statement, e.g. 
+
+----
+
 $ nickle
 > int x
 + = 0
 + ;
 >
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Quit</title>
-<para>
-The <literal>quit</literal> command exits Nickle.
-An optional argument specifies the return value.
-<informalexample><screen>
+----
+
+== Quit
+
+The `quit` command exits Nickle.
+An optional argument specifies the return value. 
+
+----
+
 $ nickle
 > quit
 $
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Print</title>
-<para>
-The <literal>print</literal> command provides information such as visibility, type, and value, about a name.
-It need not be the name of a variable; functions, namespaces, etc. may also be printed.
-<informalexample><screen><![CDATA[
+----
+
+== Print
+
+The `print` command provides information such as visibility, type, and value, about a name.
+It need not be the name of a variable; functions, namespaces, etc.
+may also be printed. 
+
+----
+
 $ nickle
 > int x = 2;
 > print x
@@ -69,15 +73,15 @@ void hello ()
 {
     printf ("hello, world\n");
 }
-> 
-]]></screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Undefine</title>
-<para>
-A defined name can be undefined, e.g.
-<informalexample><screen>
+>
+----
+
+== Undefine
+
+A defined name can be undefined, e.g. 
+
+----
+
 $ nickle
 > print x
 No symbol "x" in namespace
@@ -88,21 +92,19 @@ global int x = 0;
 > print x
 No symbol "x" in namespace
 >
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Loading files</title>
-<para>
-The <literal>load</literal> and <literal>library</literal> commands evaluate a file at runtime like the <literal>-f</literal> and <literal>-l</literal> flags, respectively.
-</para>
-</sect2>
-
-<sect2><title>Edit</title>
-<para>
-The <literal>edit</literal> command invokes <literal>$EDITOR</literal> on the name given as an argument.
-This is particularly useful to change a function while in interactive mode.
-<informalexample><screen>
+----
+
+== Loading files
+
+The `load` and `library` commands evaluate a file at runtime like the `-f` and `-l` flags, respectively. 
+
+== Edit
+
+The `edit` command invokes `$EDITOR` on the name given as an argument.
+This is particularly useful to change a function while in interactive mode. 
+
+----
+
 $ nickle
 > void function hello() { printf("hello, world\n"); }
 > edit hello
@@ -118,17 +120,17 @@ void hello ()
 {
     printf ("goodbye, cruel world\n");
 }
-> 
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>History</title>
-<para>
-The <literal>history</literal> command retrieves the values of the last ten expressions.
+>
+----
+
+== History
+
+The `history` command retrieves the values of the last ten expressions.
 With an argument, it instead retrieves the values of that many preceeding values.
-With two arguments, it retrieves the specified range in history.
-<informalexample><screen>
+With two arguments, it retrieves the specified range in history. 
+
+----
+
 $ nickle
 ...
 > history
@@ -154,16 +156,13 @@ $182    2
 $183    2
 $184    0
 $185    10
-</screen></informalexample>
-</para>
-<para>
-These history items may be named and used directly:
-<informalexample><screen>
+----
+
+These history items may be named and used directly: 
+
+----
+
 > $180 ** 2
 144
 >
-</screen></informalexample>
-</para>
-</sect2>
-
-</sect1>
+----
diff --git a/doc/tutorial/basics/invoke.adoc b/doc/tutorial/basics/invoke.adoc
new file mode 100644
index 0000000..d111d53
--- /dev/null
+++ b/doc/tutorial/basics/invoke.adoc
@@ -0,0 +1,36 @@
+
+= Invocation
+// <cmdsynopsis>
+// <command>nickle</command>
+// <arg>-f <replaceable>file</replaceable></arg>
+// <arg>-l <replaceable>file</replaceable></arg>
+// <arg>-e <replaceable>expr</replaceable></arg>
+// <arg><replaceable>script</replaceable></arg>
+// <arg>--</arg>
+// <arg><replaceable>arg ...</replaceable></arg>
+// </cmdsynopsis>
+
+
+`-f`::
+Evaluate [replaceable]``file``. 
+
+`-l`::
+Evaluate [replaceable]``file`` like ``-f``, but expect it to be in ``$NICKLEPATH``. 
+
+`-e`::
+Evaluate a Nickle expression, e.g. 
++
+
+
+----
+
+$ nickle -e 3**4
+81
+$
+----
+`script`::
+If Nickle encounters an unflagged argument, it assumes it to be the name of a script, which it runs.
+If a `$$.$$nicklerc` file is available, it will be evaluated first.
+No more arguments are processed; the rest of the line is given to the script as its arguments. 
+
+Without `-e` or a script as an argument, Nickle runs interactively, accepting standard input and writing to standard output.
diff --git a/doc/tutorial/basics/invoke.sgml b/doc/tutorial/basics/invoke.sgml
deleted file mode 100644
index 21ec5c1..0000000
--- a/doc/tutorial/basics/invoke.sgml
+++ /dev/null
@@ -1,55 +0,0 @@
-<sect1><title>Invocation</title>
-
-<cmdsynopsis>
-<command>nickle</command>
-<arg>-f <replaceable>file</replaceable></arg>
-<arg>-l <replaceable>file</replaceable></arg>
-<arg>-e <replaceable>expr</replaceable></arg>
-<arg><replaceable>script</replaceable></arg>
-<arg>--</arg>
-<arg><replaceable>arg ...</replaceable></arg>
-</cmdsynopsis>
-
-<variablelist>
-
-<varlistentry><term><literal>-f</literal></term>
-<listitem><para>
-Evaluate <replaceable>file</replaceable>.
-</para></listitem>
-</varlistentry>
-
-<varlistentry><term><literal>-l</literal></term>
-<listitem><para>
-Evaluate <replaceable>file</replaceable> like <literal>-f</literal>, but expect it to be in <literal>$NICKLEPATH</literal>.
-</para></listitem>
-</varlistentry>
-
-<varlistentry><term><literal>-e</literal></term>
-<listitem>
-<para>
-Evaluate a Nickle expression, e.g.
-</para>
-<informalexample><screen>
-$ nickle -e 3**4
-81
-$
-</screen></informalexample>
-</listitem>
-</varlistentry>
-
-<varlistentry><term><literal>script</literal></term>
-<listitem><para>
-If Nickle encounters an unflagged argument, it assumes it to be the name of a script, which it runs.
-If a <literal>.nicklerc</literal> file is available, it will
-be evaluated first.
-No more arguments are processed; the rest of the line is given to the script as its arguments.
-</para></listitem>
-</varlistentry>
-
-</variablelist>
-
-<para>
-Without <literal>-e</literal> or a script as an argument, Nickle runs interactively, accepting standard input and writing to standard output.
-</para>
-
-</sect1>
diff --git a/doc/tutorial/builtins/io.adoc b/doc/tutorial/builtins/io.adoc
new file mode 100644
index 0000000..e5aca87
--- /dev/null
+++ b/doc/tutorial/builtins/io.adoc
@@ -0,0 +1,208 @@
+
+= Input and Output
+
+Input and output in Nickle are mostly accomplished through the File builtin namespace; some top-level builtins refer to those functions.
+Nickle's input and output are modeled, as much of the language is, on C, but many changes have been made. 
+
+== Opening and closing files
+
+The functions in the File namespace use the `file` primitive type to describe filehandles.
+Three are predefined, with their usual meanings: ``stdin``, ``stdout``, and ``stderr``.
+For many functions in File, there is a top-level builtin which assumes one of these standard streams.
+Other files may be read and written by opening them: 
+// <synopsis>
+// file open(string path, string mode)
+// </synopsis>
+
+The first string gives the path to the file to be opened; the second is one of: 
+
+* "r" to open read-only, starting at the beginning of the file.
+* "r+" to open read-write, starting at the beginning of the file.
+* "w" to create or truncate the file and open write-only.
+* "w+" to create or truncate the file and open read-write.
+* "a" to open write-only, appending to the end of the file.
+* "a+" to open read-write, appending to the end of the file.
+
+If successful, a filehandle will be returned that can then be used. 
+
+Nickle can also open pipes to other programs, reading or writing to their stdouts or stdins; these are also treated as ``file``s, and the difference is transparent to the functions that manipulate them.
+Pipes are opened with `pipe` rather than ``open``; otherwise they are treated identically to flat files. 
+// <synopsis>
+// file pipe(string path, string[*] argv, string mode)
+// </synopsis>
+
+The first string refers to the program to be run; `argv` is an array of the arguments to pass to it.
+By convention, `argv[0]` should be the name of the program.
+Finally, `mode` is one of those for ``open``; reading from the pipe reads from the program's stdout, and writing to the pipe writes to the program's stdin.
+For example, 
+
+----
+
+$ nickle
+> string[*] args = {"-a"};
+> file ls = File::pipe ( "ls", args, "r" );
+> do printf ( "%s\n", File::fgets ( ls ) );
++ while ( ! File::end ( ls ) );
+bin
+man
+nickle
+share
+----
+
+When a file is no longer needed, it should be closed. 
+// <synopsis>
+// void close(file f)
+// </synopsis>
+
+
+----
+
+> File::close ( ls );
+----
+
+== Flush
+
+Output written to a file is not immediately written, but buffered until an appropriate time.
+Ordinarily, this is not noticed; if, however, it is important to know that all buffers have been written to a file, they can be flushed: 
+// <synopsis>
+// void flush (file f)
+// </synopsis>
+
+
+== End
+
+Returns true if the file is at end-of-file, otherwise returns false. 
+// <synopsis>
+// bool end (file f)
+// </synopsis>
+
+
+== Characters and strings
+
+Individual characters can be read and written using ``getc``, ``getchar``, ``putc``, and ``putchar``. 
+// <synopsis>
+// int getc(file f)
+// </synopsis>
+
+// <synopsis>
+// int getchar()
+// </synopsis>
+
+// <synopsis>
+// int putc(int c,file f)
+// </synopsis>
+
+// <synopsis>
+// void putchar(int c)
+// </synopsis>
+
+A character can be pushed back onto the stream with `ungetc` or ``ungetchar``. 
+// <synopsis>
+// int ungetc(int c, file f)
+// </synopsis>
+
+// <synopsis>
+// int ungetchar(int c)
+// </synopsis>
+
+Strings can be read, a line at a time, using `fgets` and ``gets``. 
+// <synopsis>
+// string fgets(file f)
+// </synopsis>
+
+// <synopsis>
+// string gets()
+// </synopsis>
+
+All of these are like their C counterparts, with the exception noted in the following section. 
+
+== Unicode and characters vs. bytes
+
+Unicode is a standard for representing characters, like ASCII.
+However, Unicode is designed to be able to support a much larger range of characters; in fact, every character in every alphabet worldwide.
+It is optimized so standard ASCII characters retain their ASCII codes, and characters are not larger than they have to be.
+Because of its advantages, and the possibility that it may become more standard than ASCII, and because there is no reason not to, Nickle reads and writes Unicode.
+This is entirely transparent to the user/programmer. 
+
+However, there is one situation in which the programmer will notice (disregarding the case where the programmer finds himself typing on a Sanskrit keyboard): extended characters that do not stand for themselves the same in ASCII and Unicode are _not_ one byte long; they can be as many as four for the really obscure characters.
+Therefore, unlike in C, __characters cannot be counted on to be the same as bytes__.
+For this reason, Nickle provides the following functions: 
+// <synopsis>
+// int putb(int c,file f)
+// </synopsis>
+
+// <synopsis>
+// int getb(file f)
+// </synopsis>
+
+// <synopsis>
+// int ungetb(file f)
+// </synopsis>
+
+These operate the same as ``putc``, ``getc``, and ``ungetc``, but will always read or write one byte at a time, regardless of character representation. 
+
+== Formatted I/O
+
+Nickle provides functions such as ``printf``, ``sprintf``, and `scanf` to perform formatted input and output.
+These functions perform like their C counterparts, with the following exceptions: 
+
+* The precision of a field in the format string may be specified to be '-', which means infinite precision.
+* The %g format specifier requires a number, and prints it in the best way possible. For example: 
++
+
+----
+
+> printf("%g %g %g\n", 1, 1/3, sqrt(2));
+1 0.{3} 1.414213562373095
+----
+* The %v format specifier will attempt to find the best way to print whatever value it is given. This is a great way to print polys whose types will not be known ahead of time. 
++
+
+----
+
+> printf("%v %v %v\n", 1/3, "hello", fork 4!);
+(1/3) "hello" %38
+----
+Notice that it can even figure out difficult things like the thread returned by 'fork'. 
+
+
+== At the top level
+
+Many functions in the File namespace have counterparts builtin at the top level; these do not need to be imported from File because they are automatically present. 
+
+* int printf(string fmt, poly args...) is the same as ``File::printf``.
+* string printf(string fmt, poly args...) is the same as ``File::sprintf``.
+* void putchar(int c) is the same as ``File::putchar``.
+
+File also contains a namespace called FileGlobals, which is automatically imported.
+It contains the following definitions: 
+
+----
+
+public int scanf (string format, *poly args...)
+{
+        return File::vfscanf (stdin, format, args);
+}
+
+public int vscanf (string format, (*poly)[*] args)
+{
+        return File::vfscanf (stdin, format, args);
+}    
+
+public string gets ()
+{
+        return File::fgets (stdin);
+}
+
+public int getchar ()
+{
+        return File::getc (stdin);
+}
+
+public void ungetchar (int ch)
+{
+        File::ungetc (ch, stdin);
+}
+----
+Thus, ``scanf``, ``vscanf``, ``gets``, ``getchar``, and `ungetchar` call the appropriate functions in File and return their results.
+The other functions in File must be imported as normal. 
\ No newline at end of file
diff --git a/doc/tutorial/builtins/io.sgml b/doc/tutorial/builtins/io.sgml
deleted file mode 100644
index afb946a..0000000
--- a/doc/tutorial/builtins/io.sgml
+++ /dev/null
@@ -1,219 +0,0 @@
-<sect1><title>Input and Output</title>
-<para>
-Input and output in Nickle are mostly accomplished through the File builtin namespace; some top-level builtins refer to those functions.
-Nickle's input and output are modeled, as much of the language is, on C, but many changes have been made.
-</para>
-
-<sect2><title>Opening and closing files</title>
-<para>
-The functions in the File namespace use the <literal>file</literal> primitive type to describe filehandles.
-Three are predefined, with their usual meanings: <literal>stdin</literal>, <literal>stdout</literal>, and <literal>stderr</literal>.
-For many functions in File, there is a top-level builtin which assumes one of these standard streams.
-Other files may be read and written by opening them:
-</para>
-<synopsis>
-file open(string path, string mode)
-</synopsis>
-<para>
-The first string gives the path to the file to be opened; the second is one of:
-</para>
-<itemizedlist>
-<listitem><para>"r" to open read-only, starting at the beginning of the file.</para></listitem>
-<listitem><para>"r+" to open read-write, starting at the beginning of the file.</para></listitem>
-<listitem><para>"w" to create or truncate the file and open write-only.</para></listitem>
-<listitem><para>"w+" to create or truncate the file and open read-write.</para></listitem>
-<listitem><para>"a" to open write-only, appending to the end of the file.</para></listitem>
-<listitem><para>"a+" to open read-write, appending to the end of the file.</para></listitem>
-</itemizedlist>
-<para>
-If successful, a filehandle will be returned that can then be used.
-</para>
-<para>
-Nickle can also open pipes to other programs, reading or writing to their stdouts or stdins; these are also treated as <literal>file</literal>s, and the difference is transparent to the functions that manipulate them.
-Pipes are opened with <literal>pipe</literal> rather than <literal>open</literal>; otherwise they are treated identically to flat files.
-</para>
-<synopsis>
-file pipe(string path, string[*] argv, string mode)
-</synopsis>
-<para>
-The first string refers to the program to be run; <literal>argv</literal> is an array of the arguments to pass to it.
-By convention, <literal>argv[0]</literal> should be the name of the program.
-Finally, <literal>mode</literal> is one of those for <literal>open</literal>; reading from the pipe reads from the program's stdout, and writing to the pipe writes to the program's stdin.
-For example,
-<informalexample><screen>
-$ nickle
-> string[*] args = {"-a"};
-> file ls = File::pipe ( "ls", args, "r" );
-> do printf ( "%s\n", File::fgets ( ls ) );
-+ while ( ! File::end ( ls ) );
-bin
-man
-nickle
-share
-</screen></informalexample>
-</para>
-<para>
-When a file is no longer needed, it should be closed.
-</para>
-<synopsis>
-void close(file f)
-</synopsis>
-<informalexample><screen>
-> File::close ( ls );
-</screen></informalexample>
-</sect2>
-
-<sect2><title>Flush</title>
-<para>
-Output written to a file is not immediately written, but buffered until an appropriate time.
-Ordinarily, this is not noticed; if, however, it is important to know that all buffers have been written to a file, they can be flushed:
-</para>
-<synopsis>
-void flush (file f)
-</synopsis>
-</sect2>
-
-<sect2><title>End</title>
-<para>
-Returns true if the file is at end-of-file, otherwise returns false.
-</para>
-<synopsis>
-bool end (file f)
-</synopsis>
-</sect2>
-
-<sect2><title>Characters and strings</title>
-<para>
-Individual characters can be read and written using <literal>getc</literal>, <literal>getchar</literal>, <literal>putc</literal>, and <literal>putchar</literal>.
-</para>
-<synopsis>
-int getc(file f)
-</synopsis>
-<synopsis>
-int getchar()
-</synopsis>
-<synopsis>
-int putc(int c,file f)
-</synopsis>
-<synopsis>
-void putchar(int c)
-</synopsis>
-<para>
-A character can be pushed back onto the stream with <literal>ungetc</literal> or <literal>ungetchar</literal>.
-</para>
-<synopsis>
-int ungetc(int c, file f)
-</synopsis>
-<synopsis>
-int ungetchar(int c)
-</synopsis>
-<para>
-Strings can be read, a line at a time, using <literal>fgets</literal> and <literal>gets</literal>.
-</para>
-<synopsis>
-string fgets(file f)
-</synopsis>
-<synopsis>
-string gets()
-</synopsis>
-<para>
-All of these are like their C counterparts, with the exception noted in the following section.
-</para>
-</sect2>
-
-<sect2><title>Unicode and characters vs. bytes</title>
-<para>
-Unicode is a standard for representing characters, like ASCII.
-However, Unicode is designed to be able to support a much larger range of characters; in fact, every character in every alphabet worldwide.
-It is optimized so standard ASCII characters retain their ASCII codes, and characters are not larger than they have to be.
-Because of its advantages, and the possibility that it may become more standard than ASCII, and because there is no reason not to, Nickle reads and writes Unicode.
-This is entirely transparent to the user/programmer.
-</para>
-<para>
-However, there is one situation in which the programmer will notice (disregarding the case where the programmer finds himself typing on a Sanskrit keyboard): extended characters that do not stand for themselves the same in ASCII and Unicode are <emphasis>not</emphasis> one byte long; they can be as many as four for the really obscure characters.
-Therefore, unlike in C, <emphasis>characters cannot be counted on to be the same as bytes</emphasis>.
-For this reason, Nickle provides the following functions:
-</para>
-<synopsis>
-int putb(int c,file f)
-</synopsis>
-<synopsis>
-int getb(file f)
-</synopsis>
-<synopsis>
-int ungetb(file f)
-</synopsis>
-<para>
-These operate the same as <literal>putc</literal>, <literal>getc</literal>, and <literal>ungetc</literal>, but will always read or write one byte at a time, regardless of character representation.
-</para>
-</sect2>
-
-<sect2><title>Formatted I/O</title>
-<para>
-Nickle provides functions such as <literal>printf</literal>, <literal>sprintf</literal>, and <literal>scanf</literal> to perform formatted input and output.
-These functions perform like their C counterparts, with the following exceptions:
-</para>
-<itemizedlist>
-<listitem><para>The precision of a field in the format string may be specified to be '-', which means infinite precision.</para></listitem>
-<listitem><para>The %g format specifier requires a number, and prints it in the best way possible. For example:
-<informalexample><screen>
-> printf("%g %g %g\n", 1, 1/3, sqrt(2));
-1 0.{3} 1.414213562373095
-</screen></informalexample>
-</para></listitem>
-<listitem><para>
-The %v format specifier will attempt to find the best way to print whatever value it is given.
-This is a great way to print polys whose types will not be known ahead of time.
-<informalexample><screen>
-> printf("%v %v %v\n", 1/3, "hello", fork 4!);
-(1/3) "hello" %38
-</screen></informalexample>
-Notice that it can even figure out difficult things like the thread returned by 'fork'.
-</para></listitem>
-</itemizedlist>
-</sect2>
-
-<sect2><title>At the top level</title>
-<para>
-Many functions in the File namespace have counterparts builtin at the top level; these do not need to be imported from File because they are automatically present.
-</para>
-<itemizedlist>
-<listitem><para>int printf(string fmt, poly args...) is the same as <literal>File::printf</literal>.</para></listitem>
-<listitem><para>string printf(string fmt, poly args...) is the same as <literal>File::sprintf</literal>.</para></listitem>
-<listitem><para>void putchar(int c) is the same as <literal>File::putchar</literal>.</para></listitem>
-</itemizedlist>
-<para>
-File also contains a namespace called FileGlobals, which is automatically imported.
-It contains the following definitions:
-<informalexample><screen>
-public int scanf (string format, *poly args...)
-{
-        return File::vfscanf (stdin, format, args);
-}
-
-public int vscanf (string format, (*poly)[*] args)
-{
-        return File::vfscanf (stdin, format, args);
-}    
-
-public string gets ()
-{
-        return File::fgets (stdin);
-}
-
-public int getchar ()
-{
-        return File::getc (stdin);
-}
-
-public void ungetchar (int ch)
-{
-        File::ungetc (ch, stdin);
-}
-</screen></informalexample>
-Thus, <literal>scanf</literal>, <literal>vscanf</literal>, <literal>gets</literal>, <literal>getchar</literal>, and <literal>ungetchar</literal> call the appropriate functions in File and return their results.
-The other functions in File must be imported as normal.
-</para>
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/builtins/math.sgml b/doc/tutorial/builtins/math.adoc
similarity index 52%
rename from doc/tutorial/builtins/math.sgml
rename to doc/tutorial/builtins/math.adoc
index 0d5249d..98f1c67 100644
--- a/doc/tutorial/builtins/math.sgml
+++ b/doc/tutorial/builtins/math.adoc
@@ -1,49 +1,47 @@
-<sect1><title>Math</title>
 
-<sect2><title>Numbers</title>
-<para>
+= Math
+
+== Numbers
+
 The three numeric types in Nickle--int, rational, and real--have a hierarchical relationship.
 Specifically, int is a subset of rational, which is a subset of real.
-Ints and rationals are stored internally in infinite precision, and printed as precisely as possible (rationals with repeating portions are represented with curly braces to allow more precision in printing; see the section on Expressions for a discussion of rational constants).
-Reals are stored in finite, floating-point representations.
-The mantissa defaults to 256 bits long, but this number can be changed.
-</para>
-<para>
+Ints and rationals are stored internally in infinite precision, and printed as precisely as possible (rationals with repeating portions are represented with curly braces to allow more precision in printing; see the section on Expressions for a discussion of rational constants). Reals are stored in finite, floating-point representations.
+The mantissa defaults to 256 bits long, but this number can be changed. 
+
 Whenever performing calculations, Nickle will keep numbers in their most specific format.
 For example, the result of '4/2' is an int, because although the result (2) is a rational, it is also an int, and int is more specific.
 Similarly, reals are not always in imprecise floating representation; if they are known exactly, they will be represented as rationals or ints.
-Nickle will only produce imprecise reals when it has to, as in square roots and logarithms.
-</para>
-</sect2>
+Nickle will only produce imprecise reals when it has to, as in square roots and logarithms. 
+
+== Operators
 
-<sect2><title>Operators</title>
-<para>
 In order to do the Right Thing for a desk calculator, Nickle provides several operators that are not present in C; these are extremely useful.
 To force division to produce an integer, even if the result would be a rational, use the '//' integer divide operator, which always rounds its results to ints.
 Nickle also has an exponentiation operator '**', which behaves correctly for all exponents, including negative and fractional.
 Therefore, sqrt(x) is the same as x**.5, and 1/x is the same as x**-1.
-Finally, it provides a factorial operator '!'.
-</para>
-</sect2>
-
-<sect2><title>The Math namespace</title>
-<para>
-Nickle provides the builtin namespace Math for useful functions such as trigonometric functions, logarithms, as well as useful constants such as <literal>pi</literal> and <literal>e</literal>.
-</para>
-
-<sect3><title>Logarithms</title>
-<synopsis>
-real log ( real a )
-</synopsis>
-<synopsis>
-real log10 ( real a )
-</synopsis>
-<synopsis>
-real log2 ( real a )
-</synopsis>
-<para>
-The logarithm of <literal>a</literal> in base e, ten, and two, respectively.
-<informalexample><screen>
+Finally, it provides a factorial operator '!'. 
+
+== The Math namespace
+
+Nickle provides the builtin namespace Math for useful functions such as trigonometric functions, logarithms, as well as useful constants such as `pi` and ``e``. 
+
+=== Logarithms
+// <synopsis>
+// real log ( real a )
+// </synopsis>
+
+// <synopsis>
+// real log10 ( real a )
+// </synopsis>
+
+// <synopsis>
+// real log2 ( real a )
+// </synopsis>
+
+The logarithm of `a` in base e, ten, and two, respectively. 
+
+----
+
 $ nickle
 > log ( Math::e )
 1.000000000000000
@@ -51,56 +49,53 @@ $ nickle
 1.999999999999999
 > log2 ( 16 )
 3.999999999999999
-> 
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Trigonometric functions</title>
-<synopsis>
-real sin ( real a )
-</synopsis>
-<synopsis>
-real cos ( real a )
-</synopsis>
-<synopsis>
-real tan ( real a )
-</synopsis>
-<synopsis>
-real asin ( real a )
-</synopsis>
-<synopsis>
-real acos ( real a )
-</synopsis>
-<synopsis>
-real atan ( real a )
-</synopsis>
-<para>
-The sine, cosine, and tangent of <literal>a</literal>, and the inverse functions.
-<informalexample><screen>
+>
+----
+
+=== Trigonometric functions
+// <synopsis>
+// real sin ( real a )
+// </synopsis>
+
+// <synopsis>
+// real cos ( real a )
+// </synopsis>
+
+// <synopsis>
+// real tan ( real a )
+// </synopsis>
+
+// <synopsis>
+// real asin ( real a )
+// </synopsis>
+
+// <synopsis>
+// real acos ( real a )
+// </synopsis>
+
+// <synopsis>
+// real atan ( real a )
+// </synopsis>
+
+The sine, cosine, and tangent of ``a``, and the inverse functions. 
+
+----
+
 $ nickle
 > sin ( pi ) ** 2 + cos ( pi ) **2
 1
 > atan ( 1 ) * 4
 3.141592653589793
-> 
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Constants</title>
-<synopsis>
-protected real e
-</synopsis>
-<synopsis>
-real pi
-</synopsis>
-<para>
-<literal>pi</literal> and <literal>e</literal> define the usual constants (3.14..., 2.72...).
-<literal>e</literal> is protected and must be called <literal>Math::e</literal> to allow ordinary use of the name <literal>e</literal>.
-</para>
-</sect3>
-
-</sect2>
-
-</sect1>
+>
+----
+
+=== Constants
+// <synopsis>
+// protected real e
+// </synopsis>
+
+// <synopsis>
+// real pi
+// </synopsis>
+
+`pi` and `e` define the usual constants (3.14..., 2.72...). ``e`` is protected and must be called `Math::e` to allow ordinary use of the name ``e``. 
\ No newline at end of file
diff --git a/doc/tutorial/builtins/strings.adoc b/doc/tutorial/builtins/strings.adoc
new file mode 100644
index 0000000..28a712b
--- /dev/null
+++ b/doc/tutorial/builtins/strings.adoc
@@ -0,0 +1,129 @@
+
+= Strings
+
+Unlike in C, strings in Nickle are not arrays of or pointers to individual characters.
+Consistent with its pattern of providing primitive datatypes for types for things that make sense (e.g. `file` instead of integer file handles), Nickle provides the `string` type.
+This has several interesting differences from C-style strings: 
+
+* In Nickle, strings are immutable--individual characters may not be changed.
+* Strings are, as with everything else, assigned and passed by-value. See the section on Copy semantics for details. 
+
+
+== Operators
+
+Two useful operators have been overloaded to allow sane manipulation of strings: '+' and array subscript ('[]'). 
+
+=== Subscripting
+
+Although they are not arrays of characters, it is often useful to access a string a character at a time; the array subscript operator has been overloaded to allow this.
+For example: 
+
+----
+
+> string s = "hello, world";
+> s[0]
+104
+> s[1]
+101
+> s[2]
+108
+> s[3]
+108
+> s[4]
+111
+>
+----
+
+Those are the integer representations of each character; they are most likely in ASCII, but not necessarily--see the section on Unicode in the I/O section.
+The String namespace provides `new` to recreate a string from these integer character representations, regardless of ASCII or Unicode: 
+// <synopsis>
+// string new(int c)
+// </synopsis>
+
+// <synopsis>
+// string new(int[*] cv)
+// </synopsis>
+
+For instance, 
+
+----
+
+> String::new(s[0])
+"h"
+----
+
+=== Concatenation
+
+On strings, '+' is the concatenation operator.
+For example, 
+
+----
+
+> string s = "hello", t = "world"; 
+> s = s + ", ";
+> t += "!";
+> s+t
+"hello, world!"
+----
+
+== String namespace
+
+In addition, the String namespace provides several useful functions that facilitate using strings, including the following. 
+
+=== Length
+// <synopsis>
+// int length ( string s )
+// </synopsis>
+
+Returns the number of characters in ``s``.
+For example, 
+
+----
+
+$ nickle
+> String::length ( "hello, world" ) 
+12
+>
+----
+
+=== Index
+// <synopsis>
+// int index ( string t, string p )
+// </synopsis>
+
+// <synopsis>
+// int rindex ( string t, string p )
+// </synopsis>
+
+Returns the index of the first occurence of the substring `p` in ``t``, or -1 if `p` is not in ``t``; `rindex` returns the last occurance instead.
+For example, 
+
+----
+
+$ nickle
+> String::index ( "hello, world", "or" ) 
+8
+> String::index ( "hello, world", "goodbye" )
+-1
+> String::rindex ( "hello, world", "o" )
+8
+----
+
+=== Substr
+// <synopsis>
+// string substr ( string s, int i, int l )
+// </synopsis>
+
+Returns the substring of `s` which begins at index `i` and is `l` characters long.
+If `l` is negative, returns the substring of that length which preceeds `i` instead.
+For example, 
+
+----
+
+$ nickle
+> String::substr ( "hello, world", 8, 2 ) 
+"or"
+> String::substr ( "hello, world", 8, -4 )
+"o, w"
+>
+----
diff --git a/doc/tutorial/builtins/strings.sgml b/doc/tutorial/builtins/strings.sgml
deleted file mode 100644
index f8af053..0000000
--- a/doc/tutorial/builtins/strings.sgml
+++ /dev/null
@@ -1,138 +0,0 @@
-<sect1><title>Strings</title>
-<para>
-Unlike in C, strings in Nickle are not arrays of or pointers to individual characters.
-Consistent with its pattern of providing primitive datatypes for types for things that make sense (e.g. <literal>file</literal> instead of integer file handles), Nickle provides the <literal>string</literal> type.
-This has several interesting differences from C-style strings:
-</para>
-<itemizedlist>
-<listitem><para>In Nickle, strings are immutable--individual characters may not be changed.</para></listitem>
-<listitem><para>
-Strings are, as with everything else, assigned and passed by-value.
-See the section on Copy semantics for details.
-</para></listitem>
-</itemizedlist>
-
-<sect2><title>Operators</title>
-<para>
-Two useful operators have been overloaded to allow sane manipulation of strings: '+' and array subscript ('[]').
-</para>
-
-<sect3><title>Subscripting</title>
-<para>
-Although they are not arrays of characters, it is often useful to access a string a character at a time; the array subscript operator has been overloaded to allow this.
-For example:
-<informalexample><screen>
-> string s = "hello, world";
-> s[0]
-104
-> s[1]
-101
-> s[2]
-108
-> s[3]
-108
-> s[4]
-111
-> 
-</screen></informalexample>
-</para>
-<para>
-Those are the integer representations of each character; they are most likely in ASCII, but not necessarily--see the section on Unicode in the I/O section.
-The String namespace provides <literal>new</literal> to recreate a string from these integer character representations, regardless of ASCII or Unicode:
-</para>
-<synopsis>
-string new(int c)
-</synopsis>
-<synopsis>
-string new(int[*] cv)
-</synopsis>
-<para>
-For instance,
-<informalexample><screen>
-> String::new(s[0])
-"h"
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Concatenation</title>
-<para>
-On strings, '+' is the concatenation operator.
-For example,
-<informalexample><screen>
-> string s = "hello", t = "world"; 
-> s = s + ", ";
-> t += "!";
-> s+t
-"hello, world!"
-</screen></informalexample>
-</para>
-</sect3>
-
-</sect2>
-
-<sect2><title>String namespace</title>
-<para>
-In addition, the String namespace provides several useful functions that facilitate using strings, including the following.
-</para>
-
-<sect3><title>Length</title>
-<synopsis>
-int length ( string s )
-</synopsis>
-<para>
-Returns the number of characters in <literal>s</literal>.
-For example,
-<informalexample><screen>
-$ nickle
-> String::length ( "hello, world" ) 
-12
-> 
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Index</title>
-<synopsis>
-int index ( string t, string p )
-</synopsis>
-<synopsis>
-int rindex ( string t, string p )
-</synopsis>
-<para>
-Returns the index of the first occurence of the substring <literal>p</literal> in <literal>t</literal>, or -1 if <literal>p</literal> is not in <literal>t</literal>; <literal>rindex</literal> returns the last occurance instead.
-For example,
-<informalexample><screen>
-$ nickle
-> String::index ( "hello, world", "or" ) 
-8
-> String::index ( "hello, world", "goodbye" )
--1
-> String::rindex ( "hello, world", "o" )
-8
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Substr</title>
-<synopsis>
-string substr ( string s, int i, int l )
-</synopsis>
-<para>
-Returns the substring of <literal>s</literal> which begins at index <literal>i</literal> and is <literal>l</literal> characters long.
-If <literal>l</literal> is negative, returns the substring of that length which preceeds <literal>i</literal> instead.
-For example,
-<informalexample><screen>
-$ nickle
-> String::substr ( "hello, world", 8, 2 ) 
-"or"
-> String::substr ( "hello, world", 8, -4 )
-"o, w"
->
-</screen></informalexample>
-</para>
-</sect3>
-
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/intro/expressions.adoc b/doc/tutorial/intro/expressions.adoc
new file mode 100644
index 0000000..5197788
--- /dev/null
+++ b/doc/tutorial/intro/expressions.adoc
@@ -0,0 +1,257 @@
+
+= Nickle Expressions
+
+Expression types are listed in order of increasing precedence. 
+
+== Variable declarations
+
+Variable declarations are expressions in Nickle; the value of a declaration is the value of the last variable with an initialization expression.
+For example, 
+
+----
+
+> int val;
+> val = (int i=2, j=3);
+> print val
+global int val = 3;
+----
+
+If no initialization expressions are present, it is an error to use the value of the expression. 
+
+----
+
+> val = (int i,j);
+Unhandled exception "uninitialized_value" at <stdin>:73
+        "Uninitialized value"
+----
+
+Because they are expressions, declarations can be used in contructs such as: 
+
+----
+
+for (int i = 0; i  10; i++)
+{
+        
+}
+----
+
+== Anonymous function declarations
+
+Functions may be declared anonymously and used immediately, e.g. 
+
+----
+
+> (int func ( int a, int b ) { return a + b; })(2,3)
+5
+----
+
+Any context available to the function at definition time will be available whenever it is executed.
+See Storage classes in the section on Variables. 
+
+== Binary operators
+
+Addition::
+`a + b`
+
+Subtraction::
+`a - b`
+
+Multiplication::
+`a * b`
+
+Division, Integer division::
+`a / b` +
+`a // b`
+
+Remainder::
+`a % b`
+
+Exponentiation::
+`a ** b`
+
+Left shift, Right shift::
+`a << b` +
+`a >> b`
+
+Binary xor, Binary and, Binary or::
+`a ^ b` +
+`a & b` +
+`a | b`
+
+Boolean and, Boolean or::
+`a && b` +
+`a || b`
+
+Equal, Not equal::
+`a == b` +
+`a != b`
+
+Less than, Less than or equal to::
+`a < b` +
+`a <= b`
+
+Greater than, Greater than or equal to::
+`a > b` +
+`a >= b`
+
+Assignment::
+`a = b`
+
+Assignment with operator::
+`a += b` +
+`a -= b` +
+`a *= b` +
+`a /= b` +
+`a //= b` +
+`a %= b` +
+`a **= b` +
+`a >>= b` +
+`a <<= b` +
+`a ^= b` +
+`a &= b` +
+`a |= b`
+
+== Unary operators
+
+Dereference:::
+`* a`
+
+Reference:::
+`& a`
+
+Negation:::
+`- a`
+
+Bitwise inverse:::
+`~ a`
+
+Logical not:::
+`! a`
+
+Factorial:::
+`a !`
+
+Increment:::
+`++a` +
+`a++`
+
+Decrement:::
+`--a` +
+`a--`
+
+== Constants
+
+=== Integer constants
+
+Integer constants with a leading zero are interpreted in octal, with a leading 0x in hex-decimal and with a leading 0b in binary.
+Here are some examples: 
+
+----
+
+12      /* 12, decimal */
+014     /* 12, octal */
+0xc     /* 12, hex */
+0b1100  /* 12, binary */
+----
+
+=== Rational constants
+
+Rational constants are the combination of an integer part, a mantissa with an initial and repeating part, and an exponent.
+All of these pieces are optional, but at least one of the parts (other than the exponent) must be present.
+If no fractional part is given, the resulting type of the value is int rather than rational.
+Some examples: 
+
+----
+
+> 12
+12
+> 12.5
+12.5
+> .34
+0.34
+> .{56}
+0.{56}
+> .34e3
+340
+> .{56}e12
+565656565656.{56}
+----
+
+=== String constants
+
+String constants are surrounded in double quotes, e.g.  `"hello,
+world"`. Characters preceded by a backslash stand for themselves,
+including double-quote (`"`) and blackslash (`\`). The following
+backslashed characters are special:
+
+* \n is newline
+* \r is carriage return
+* \b is backspace
+* \t is tab
+* \f is formfeed
+
+
+== Variables
+
+The name of a variable is replaced by the value of that variable in
+expressions.  If the name is of a pointer, preceding it with the `*`
+dereference operator yields the value of its target.
+
+== Struct and union references
+
+The construct 
+
+----
+
+struct.name
+----
+yields the element [replaceable]``name`` of the struct or union [replaceable]``struct``.
+To retrieve elements from a struct or union pointer, as in C, use 
+
+----
+
+struct->name
+----
+
+== Array references
+
+----
+
+arr[expr]
+
+arr[expr,expr,...,expr]
+----
+
+Elements of an array are indexed with square braces.  Elements of
+multidimensional arrays have indices in each dimension as in the
+second form.  Pointers to arrays can be indexed by placing the `*`
+dereference operator between the name of the array and the first
+square brace:
+
+----
+
+arr*[expr]
+----
+
+This is, however, deprecated in favor of using references to arrays, which have no such problems. 
+
+== The fork operator
+
+The fork operator evaluates its argument in a child thread.
+See the section on Concurrency. 
+
+== Comma operator
+
+----
+
+expr, expr
+----
+
+Evaluates each expression in turn, the resulting value is that of the right hand expression.
+For example, 
+
+----
+
+> 1+2, 5!, 3**4, 27/3
+9
+----
diff --git a/doc/tutorial/intro/expressions.sgml b/doc/tutorial/intro/expressions.sgml
deleted file mode 100644
index addc366..0000000
--- a/doc/tutorial/intro/expressions.sgml
+++ /dev/null
@@ -1,283 +0,0 @@
-<sect1><title>Nickle Expressions</title>
-<para>
-Expression types are listed in order of increasing precedence.
-</para>
-
-<sect2><title>Variable declarations</title>
-<para>
-Variable declarations are expressions in Nickle; the value of a declaration is the value of the last variable with an initialization expression.
-For example,
-<informalexample><screen>
-> int val;
-> val = (int i=2, j=3);
-> print val
-global int val = 3;
-</screen></informalexample>
-</para>
-<para>
-If no initialization expressions are present, it is an error to use the value of the expression.
-<informalexample><screen><![CDATA[
-> val = (int i,j);
-Unhandled exception "uninitialized_value" at <stdin>:73
-        "Uninitialized value"
-]]></screen></informalexample>
-</para>
-<para>
-Because they are expressions, declarations can be used in contructs such as:
-<informalexample><screen>
-for (int i = 0; i < 10; i++)
-{
-        
-}
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Anonymous function declarations</title>
-<para>
-Functions may be declared anonymously and used immediately, e.g.
-<informalexample><screen>
-> (int func ( int a, int b ) { return a + b; })(2,3)
-5
-</screen></informalexample>
-</para>
-<para>
-Any context available to the function at definition time will be available whenever it is executed.
-See Storage classes in the section on Variables.
-</para>
-</sect2>
-
-<sect2><title>Binary operators</title>
-<variablelist>
-<varlistentry><term>Addition</term>
-<listitem><para><literal>a</literal> + <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Subtraction</term>
-<listitem><para><literal>a</literal> - <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Multiplication</term>
-<listitem><para><literal>a</literal> * <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Division</term><term>Integer division</term>
-<listitem><simplelist>
-<member><literal>a</literal> / <literal>b</literal></member>
-<member><literal>a</literal> // <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Remainder</term>
-<listitem><para><literal>a</literal> % <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Exponentiation</term>
-<listitem><para><literal>a</literal> ** <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Left shift</term><term>Right shift</term>
-<listitem><simplelist>
-<member><literal>a</literal> << <literal>b</literal></member>
-<member><literal>a</literal> >> <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Binary xor</term><term>Binary and</term><term>Binary or</term>
-<listitem><simplelist>
-<member><literal>a</literal> ^ <literal>b</literal></member>
-<member><literal>a</literal> & <literal>b</literal></member>
-<member><literal>a</literal> | <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Boolean and</term><term>Boolean or</term>
-<listitem><simplelist>
-<member><literal>a</literal> && <literal>b</literal></member>
-<member><literal>a</literal> || <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Equal</term><term>Not equal</term>
-<listitem><simplelist>
-<member><literal>a</literal> == <literal>b</literal></member>
-<member><literal>a</literal> != <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Less than</term><term>Less than or equal to</term>
-<listitem><simplelist>
-<member><literal>a</literal> < <literal>b</literal></member>
-<member><literal>a</literal> <= <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Greater than</term><term>Greater than or equal to</term>
-<listitem><simplelist>
-<member><literal>a</literal> > <literal>b</literal></member>
-<member><literal>a</literal> >= <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Assignment</term>
-<listitem><para><literal>a</literal> = <literal>b</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Assignment with operator</term>
-<listitem><simplelist>
-<member><literal>a</literal> += <literal>b</literal></member>
-<member><literal>a</literal> -= <literal>b</literal></member>
-<member><literal>a</literal> *= <literal>b</literal></member>
-<member><literal>a</literal> /= <literal>b</literal></member>
-<member><literal>a</literal> //= <literal>b</literal></member>
-<member><literal>a</literal> %= <literal>b</literal></member>
-<member><literal>a</literal> **= <literal>b</literal></member>
-<member><literal>a</literal> >>= <literal>b</literal></member>
-<member><literal>a</literal> <<= <literal>b</literal></member>
-<member><literal>a</literal> ^= <literal>b</literal></member>
-<member><literal>a</literal> &= <literal>b</literal></member>
-<member><literal>a</literal> |= <literal>b</literal></member>
-</simplelist></listitem>
-</varlistentry>
-</variablelist>
-</sect2>
-
-<sect2><title>Unary operators</title>
-<variablelist>
-<varlistentry><term>Dereference:</term>
-<listitem><para> * <literal>a</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Reference:</term>
-<listitem><para> & <literal>a</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Negation:</term>
-<listitem><para> - <literal>a</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Bitwise inverse:</term>
-<listitem><para> ~ <literal>a</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Logical not:</term>
-<listitem><para> ! <literal>a</literal></para></listitem>
-</varlistentry>
-<varlistentry><term>Factorial:</term>
-<listitem><para> <literal>a</literal> !</para></listitem>
-</varlistentry>
-<varlistentry><term>Increment:</term>
-<listitem><simplelist>
-<member> ++ <literal>a</literal></member>
-<member> <literal>a</literal> ++</member>
-</simplelist></listitem>
-</varlistentry>
-<varlistentry><term>Decrement:</term>
-<listitem><simplelist>
-<member> -- <literal>a</literal></member>
-<member> <literal>a</literal> --</member>
-</simplelist></listitem>
-</varlistentry>
-</variablelist>
-</sect2>
-
-<sect2><title>Constants</title>
-
-<sect3><title>Integer constants</title>
-<para>
-Integer constants with a leading zero are interpreted in octal, with a leading 0x in hex-decimal and with a leading 0b in binary.
-Here are some examples:
-<informalexample><screen>
-12      /* 12, decimal */
-014     /* 12, octal */
-0xc     /* 12, hex */
-0b1100  /* 12, binary */
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Rational constants</title>
-<para>
-Rational constants are the combination of an integer part, a mantissa with an initial and repeating part, and an exponent.
-All of these pieces are optional, but at least one of the parts (other than the exponent) must be present.
-If no fractional part is given, the resulting type of the value is int rather than rational.
-Some examples:
-<informalexample><screen>
-> 12
-12
-> 12.5
-12.5
-> .34
-0.34
-> .{56}
-0.{56}
-> .34e3
-340
-> .{56}e12
-565656565656.{56}
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>String constants</title>
-<para>
-String constants are surrounded in double quotes, e.g. "hello, world".
-Characters preceded by a backslash stand for themselves, including double-quote (\") and blackslash (\\).
-The following backslashed characters are special:
-</para>
-<itemizedlist>
-<listitem><para>\n is newline</para></listitem>
-<listitem><para>\r is carriage return</para></listitem>
-<listitem><para>\b is backspace</para></listitem>
-<listitem><para>\t is tab</para></listitem>
-<listitem><para>\f is formfeed</para></listitem>
-</itemizedlist>
-</sect3>
-
-</sect2>
-
-<sect2><title>Variables</title>
-<para>
-The name of a variable is replaced by the value of that variable in expressions.
-If the name is of a pointer, preceding it with the <literal>*</literal> dereference operator yields the value of its target.
-</para>
-</sect2>
-
-<sect2><title>Struct and union references</title>
-<para>
-The construct
-<informalexample><screen>
-struct.name
-</screen></informalexample>
-yields the element <replaceable>name</replaceable> of the struct or union <replaceable>struct</replaceable>.
-To retrieve elements from a struct or union pointer, as in C, use
-<informalexample><screen>
-struct->name
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Array references</title>
-<informalexample><screen>
-arr[expr]
-
-arr[expr,expr,...,expr]
-</screen></informalexample>
-<para>
-Elements of an array are indexed with square braces.
-Elements of multidimensional arrays have indices in each dimension as in the second form.
-Pointers to arrays can be indexed by placing the <literal>*</literal> dereference operator between the name of the array and the first square brace:
-<informalexample><screen>
-arr*[expr]
-</screen></informalexample>
-</para>
-<para>
-This is, however, deprecated in favor of using references to arrays, which have no such problems.
-</para>
-</sect2>
-
-<sect2><title>The fork operator</title>
-<para>
-The fork operator evaluates its argument in a child thread.
-See the section on Concurrency.
-</para>
-</sect2>
-
-<sect2><title>Comma operator</title>
-<informalexample><screen>
-expr, expr
-</screen></informalexample>
-<para>
-Evaluates each expression in turn, the resulting value is that of the right hand expression.
-For example,
-<informalexample><screen>
-> 1+2, 5!, 3**4, 27/3
-9
-</screen></informalexample>
-</para>
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/intro/functions.sgml b/doc/tutorial/intro/functions.adoc
similarity index 51%
rename from doc/tutorial/intro/functions.sgml
rename to doc/tutorial/intro/functions.adoc
index b1c8d6c..3c6efa7 100644
--- a/doc/tutorial/intro/functions.sgml
+++ b/doc/tutorial/intro/functions.adoc
@@ -1,7 +1,10 @@
-<sect1><title>Nickle Functions</title>
-<para>
-An example function might be declared like this:
-<informalexample><screen><![CDATA[
+
+= Nickle Functions
+
+An example function might be declared like this: 
+
+----
+
 int gcf ( int a, int b ) {
         int f = 1;
         for ( int i = 2; i <= abs ( a ) && i <= abs ( b ); ++i )
@@ -9,22 +12,22 @@ int gcf ( int a, int b ) {
                         f *= i;
         return f;
 }
-]]></screen></informalexample>
-</para>
-<para>
+----
+
 First comes the return type of the function, then the function name, then the list of arguments (with types), and finally the statement list in curly braces.
-If any types are left off, Nickle assumes <literal>poly</literal>.
-In any case, all typechecking is done at runtime.
-</para>
-<para>
+If any types are left off, Nickle assumes ``poly``.
+In any case, all typechecking is done at runtime. 
+
 A function can take any number of arguments.
-The final argument may be succeeded by an ellipses (...) to indicate an arbitrary, variable number of succeeding arguments, each of the type of the final argument; the last argument takes on a list value to store them.
-<informalexample><screen>
+The final argument may be succeeded by an ellipses (...) to indicate an arbitrary, variable number of succeeding arguments, each of the type of the final argument; the last argument takes on a list value to store them. 
+
+----
+
 ...
 > print sum
 int sum (int a, int b ...)
 {
-    for (int i = 0; i < dim (b); ++i)
+    for (int i = 0; i  dim (b); ++i)
         a += b[i];
     return a;
 }
@@ -34,30 +37,29 @@ int sum (int a, int b ...)
 4
 > sum(1,2,4,6)
 13
-</screen></informalexample>
-</para>
-<para>
-Functions are called as in C, with their names followed by argument values in parentheses:
-<informalexample><screen>
+----
+
+Functions are called as in C, with their names followed by argument values in parentheses: 
+
+----
+
 foo ( "hello", 7.2 );
-</screen></informalexample>
-</para>
-<para>
-Since they are first class, functions can be assigned:
-<informalexample><screen>
+----
+
+Since they are first class, functions can be assigned: 
+
+----
+
 int(int,int) a = gcf;
-</screen></informalexample>
-</para>
-<para>
-See the section on Copy semantics for details on what functions may be assigned to each other.
-</para>
-<para>
-Functions may also be declared and used anonymously:
-<informalexample><screen>
+----
+
+See the section on Copy semantics for details on what functions may be assigned to each other. 
+
+Functions may also be declared and used anonymously: 
+
+----
+
 (int func ( int a, int b ) { return a + b; })(2,3);     /* 5 */
-</screen></informalexample>
-</para>
-<para>
-Replacing the function name with the keyword <literal>func</literal> indicates its anonymity.
-</para>
-</sect1>
+----
+
+Replacing the function name with the keyword `func` indicates its anonymity. 
\ No newline at end of file
diff --git a/doc/tutorial/intro/statements.adoc b/doc/tutorial/intro/statements.adoc
new file mode 100644
index 0000000..a2786ec
--- /dev/null
+++ b/doc/tutorial/intro/statements.adoc
@@ -0,0 +1,262 @@
+
+= Control Statements in Nickle
+
+== Simple statements
+// <synopsis>
+// <replaceable>expr</replaceable>;
+// </synopsis>
+
+// <synopsis>
+// ; /* null statement */
+// </synopsis>
+
+// <synopsis>
+// { <replaceable>statement</replaceable> ... }
+// </synopsis>
+
+The simplest statement is merely an expression terminated by a semicolon; the expression is evaluated.
+A semicolon by itself is allowed but does nothing.
+One or more statements may be grouped inside curly braces to form one compound statement; each is executed in order.
+Any statements may compose the statement list, including control statements and other curly-bracketed lists. 
+
+== Conditionals
+// <synopsis>
+// if ( <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
+// </synopsis>
+
+// <synopsis>
+// else <replaceable>statement</replaceable>
+// </synopsis>
+
+`if` is used to execute a section of code only under some condition: If [replaceable]``expr`` is true, [replaceable]``statement`` is executed; otherwise control skips over it.
+For example: 
+
+----
+
+if ( x == 0 )
+        printf ( "x is zero.\n" );
+----
+
+In this case, the message will be printed only if `x` is zero. 
+
+`else` allows for a choice if the condition fails.
+It executes its [replaceable]``statement`` if the most recent `if` or `twixt` (see below) did not.
+For example, 
+
+----
+
+if ( x == 0 )
+        printf ( "x is zero.\n" );
+else
+        printf ( "x is not zero.\n" );
+----
+
+More than one option may be presented by nesting further 'if's in 'else' statements like this: 
+
+----
+
+if ( x == 0 )
+        printf ( "x is zero.\n" );
+else if ( x  0 )
+        printf ( "x is negative.\n" );
+else
+        printf ( "x is positive.\n" );
+----
+
+== Twixt
+// <synopsis>
+// twixt ( <replaceable>expr</replaceable>; <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
+// </synopsis>
+
+Ensures that the the first [replaceable]``expr`` will always have been evaluated whenever control flow passes into any part of [replaceable]``statement`` and ensures that the second [replaceable]``expr`` will be evaluated anytime control flow passes out of [replaceable]``statement``. __That order is gauranteed__.
+If a `long_jmp` target is inside [replaceable]``statement``, the first [replaceable]``expr`` will be executed before control passes to the target.
+If [replaceable]``statement`` throws an exception or ``long_jmp``s out of the ``twixt``, the second [replaceable]``expr`` will be evaluated.
+Thus, `twixt` is useful in locked operations where the statement should only be executed under a lock and that lock must be released afterwards. 
+
+----
+
+twixt ( get_lock ( ); release_lock ( ) )
+        locked_operation ( );
+----
+
+== Switch
+// <synopsis>
+// switch ( <replaceable>expr</replaceable> ) { case <replaceable>expr</replaceable>: <replaceable>statement-list</replaceable> ... default: <replaceable>statement-list</replaceable> }
+// </synopsis>
+
+Control jumps to the first `case` whose [replaceable]``expr`` evaluates to the same value as the [replaceable]``expr`` at the top.
+Unlike in C, these values do not have to be integers, or even constant.
+The optional case `default` matches any value.
+If nothing is matched and there is no ``default``, control skips the `switch` entirely.
+This example prints out a number to the screen, replacing it by a letter as though it were a poker card: 
+
+----
+
+switch ( x ) {
+        case 1:
+                printf ( "A\n" );       /* ace */
+                break;
+        case 11:
+                printf ( "J\n" );       /* jack */
+                break;
+        case 12:
+                printf ( "Q\n" );       /* queen */
+                break;
+        case 13:
+                printf ( "K\n" );       /* king */
+                break;
+        default:
+                printf ( "%d\n", x );   /* numeric */
+                break;
+}
+----
+
+Notice the ``break``s in the example.
+Once control jumps to the matching case, it continues normally: Upon exhausting that [replaceable]``statement-list``, __it does not jump out of the ``__switch__``__; it continues through the subsequent statement lists.
+Here is an example of this 'falling through': 
+
+----
+
+int x = 3;
+
+switch ( sign ( x ) ) {
+        case -1:
+                printf ( "x is negative.\n" );
+        case 1:
+                printf ( "x is positive.\n" );
+        default:
+                printf ( "x is zero.\n" );
+}
+----
+
+This prints: 
+
+----
+
+x is positive.
+x is zero.
+----
+
+Falling through may be desirable if several cases are treated similarly; however, it should be used sparingly and probably commented so it is clear you are doing it on purpose.
+This is a difficult error to catch. 
+
+== Union switch
+// <synopsis>
+// union switch ( <replaceable>union</replaceable> ) { case <replaceable>name</replaceable>: <replaceable>statement-list</replaceable> ... default: <replaceable>statement-list</replaceable> }
+// </synopsis>
+
+`union switch` is similar to ``switch``.
+It matches its ``case``s based on what name currently applies to the union's value.
+As always, `default` matches everything.
+The following example chooses the best way to print the union: 
+
+----
+
+union {
+        int a;
+        string b;
+} u;
+
+u.b = "hello";
+
+union switch ( u ) {
+        case a:
+                printf ( "%d\n", u.a );
+                break;
+        case b:
+                printf ( "%s\n", u.b );
+                break;
+}
+----
+
+In this case, it prints 'hello'. 
+
+An additional name may follow that of a case; the union's value will be available inside the case by that name.
+The switch above could have been written: 
+
+----
+
+union switch ( u ) {
+        case a num:
+                printf ( "%d\n", num );
+                break;
+        case b str:
+                printf ( "%s\n", str );
+                break;
+}
+----
+
+== Loops
+// <synopsis>
+// while ( <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
+// </synopsis>
+
+// <synopsis>
+// do <replaceable>statement</replaceable> while ( <replaceable>expr</replaceable> )
+// </synopsis>
+
+// <synopsis>
+// for ( <replaceable>expr</replaceable>; <replaceable>expr</replaceable>; <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
+// </synopsis>
+
+`while` executes [replaceable]``statement`` repeatedly as long as [replaceable]``expr`` is true.
+Control continues outside the loop when [replaceable]``expression`` becomes false.
+For example: 
+
+----
+
+int x = 0;
+while ( x  10 ) {
+        printf ( "%d\n", x );
+        ++x;
+}
+----
+
+This prints the numbers from zero to nine. 
+
+`do-while` is like ``while``, but tests the condition after each iteration rather than before.
+Thus, it is garaunteed to execute at least once.
+It is often used in input while testing for end-of-file: 
+
+----
+
+file f = File::open ( "test", "r" );
+
+do {
+        printf ( "%s\n", File::fgets ( f ) );
+} while ( ! end ( f ) );
+
+close ( f );
+----
+
+`for` begins by evaluating the first [replaceable]``expr``, which often initializes a counter variable; since declarations are expressions in Nickle, they may be used here and the counter will be local to the loop.
+Then it executes [replaceable]``statement`` as long as the second [replaceable]``expr`` is true, like ``while``.
+After each iteration, the third [replaceable]``expr`` is evaluated, which usually increments or decrements the counter variable.
+The `while` example above can also be written as the following `for` loop: 
+
+----
+
+for ( int x = 0; x  10; ++x )
+        printf ( "%d\n", x );
+----
+
+== Flow control
+// <synopsis>
+// continue
+// </synopsis>
+
+// <synopsis>
+// break
+// </synopsis>
+
+// <synopsis>
+// return <replaceable>expr</replaceable>
+// </synopsis>
+
+`continue` restarts the nearest surrounding ``do-while``, ``while``, or `for` loop by jumping directly to the conditional test.
+The iterative statement of a `for` loop will be evaluated first. 
+
+`break` leaves the nearest surrounding ``do-while``, ``while``, ``for``, or `switch` statement by jumping to its end.
+The iterative statement of a `for` loop will not be evaluated. 
+
+`return` returns from the nearest surrounding function with value [replaceable]``expr``. 
\ No newline at end of file
diff --git a/doc/tutorial/intro/statements.sgml b/doc/tutorial/intro/statements.sgml
deleted file mode 100644
index 9e2bbde..0000000
--- a/doc/tutorial/intro/statements.sgml
+++ /dev/null
@@ -1,270 +0,0 @@
-<sect1><title>Control Statements in Nickle</title>
-
-<sect2><title>Simple statements</title>
-<synopsis>
-<replaceable>expr</replaceable>;
-</synopsis>
-<synopsis>
-; /* null statement */
-</synopsis>
-<synopsis>
-{ <replaceable>statement</replaceable> ... }
-</synopsis>
-<para>
-The simplest statement is merely an expression terminated by a semicolon; the expression is evaluated.
-A semicolon by itself is allowed but does nothing.
-One or more statements may be grouped inside curly braces to form one compound statement; each is executed in order.
-Any statements may compose the statement list, including control statements and other curly-bracketed lists.
-</para>
-</sect2>
-
-<sect2><title>Conditionals</title>
-<synopsis>
-if ( <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
-</synopsis>
-<synopsis>
-else <replaceable>statement</replaceable>
-</synopsis>
-<para>
-<literal>if</literal> is used to execute a section of code only under some condition: If <replaceable>expr</replaceable> is true, <replaceable>statement</replaceable> is executed; otherwise control skips over it.
-For example:
-<informalexample><screen>
-if ( x == 0 )
-        printf ( "x is zero.\n" );
-</screen></informalexample>
-</para>
-<para>
-In this case, the message will be printed only if <literal>x</literal> is zero.
-</para>
-<para>
-<literal>else</literal> allows for a choice if the condition fails.
-It executes its <replaceable>statement</replaceable> if the most recent <literal>if</literal> or <literal>twixt</literal> (see below) did not.
-For example,
-<informalexample><screen>
-if ( x == 0 )
-        printf ( "x is zero.\n" );
-else
-        printf ( "x is not zero.\n" );
-</screen></informalexample>
-</para>
-<para>
-More than one option may be presented by nesting further 'if's in 'else' statements like this:
-<informalexample><screen>
-if ( x == 0 )
-        printf ( "x is zero.\n" );
-else if ( x < 0 )
-        printf ( "x is negative.\n" );
-else
-        printf ( "x is positive.\n" );
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Twixt</title>
-<synopsis>
-twixt ( <replaceable>expr</replaceable>; <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
-</synopsis>
-<para>
-Ensures that the the first <replaceable>expr</replaceable> will always
-have been evaluated whenever control flow passes into any part
-of <replaceable>statement</replaceable> and ensures that the
-second <replaceable>expr</replaceable> will be evaluated anytime
-control flow passes out of <replaceable>statement</replaceable>.
-<emphasis>That order is gauranteed</emphasis>.
-If a <literal>long_jmp</literal> target is inside
-<replaceable>statement</replaceable>, the
-first <replaceable>expr</replaceable> will be executed before control
-passes to the target.
-If <replaceable>statement</replaceable> throws an exception
-or <literal>long_jmp</literal>s out of the <literal>twixt</literal>, the second <replaceable>expr</replaceable> will be evaluated.
-Thus, <literal>twixt</literal> is useful in locked operations where
-the statement should only be executed under a lock and that lock must
-be released afterwards.
-<informalexample><screen>
-twixt ( get_lock ( ); release_lock ( ) )
-        locked_operation ( );
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Switch</title>
-<synopsis>
-switch ( <replaceable>expr</replaceable> ) { case <replaceable>expr</replaceable>: <replaceable>statement-list</replaceable> ... default: <replaceable>statement-list</replaceable> }
-</synopsis>
-<para>
-Control jumps to the first <literal>case</literal> whose <replaceable>expr</replaceable> evaluates to the same value as the <replaceable>expr</replaceable> at the top.
-Unlike in C, these values do not have to be integers, or even constant.
-The optional case <literal>default</literal> matches any value.
-If nothing is matched and there is no <literal>default</literal>, control skips the <literal>switch</literal> entirely.
-This example prints out a number to the screen, replacing it by a letter as though it were a poker card:
-<informalexample><screen>
-switch ( x ) {
-        case 1:
-                printf ( "A\n" );       /* ace */
-                break;
-        case 11:
-                printf ( "J\n" );       /* jack */
-                break;
-        case 12:
-                printf ( "Q\n" );       /* queen */
-                break;
-        case 13:
-                printf ( "K\n" );       /* king */
-                break;
-        default:
-                printf ( "%d\n", x );   /* numeric */
-                break;
-}
-</screen></informalexample>
-</para>
-<para>
-Notice the <literal>break</literal>s in the example.
-Once control jumps to the matching case, it continues normally: Upon exhausting that <replaceable>statement-list</replaceable>, <emphasis>it does not jump out of the <literal>switch</literal></emphasis>; it continues through the subsequent statement lists.
-Here is an example of this 'falling through':
-<informalexample><screen>
-int x = 3;
-
-switch ( sign ( x ) ) {
-        case -1:
-                printf ( "x is negative.\n" );
-        case 1:
-                printf ( "x is positive.\n" );
-        default:
-                printf ( "x is zero.\n" );
-}
-</screen></informalexample>
-</para>
-<para>
-This prints:
-<informalexample><screen>
-x is positive.
-x is zero.
-</screen></informalexample>
-</para>
-<para>
-Falling through may be desirable if several cases are treated similarly; however, it should be used sparingly and probably commented so it is clear you are doing it on purpose.
-This is a difficult error to catch.
-</para>
-</sect2>
-
-<sect2><title>Union switch</title>
-<synopsis>
-union switch ( <replaceable>union</replaceable> ) { case <replaceable>name</replaceable>: <replaceable>statement-list</replaceable> ... default: <replaceable>statement-list</replaceable> }
-</synopsis>
-<para>
-<literal>union switch</literal> is similar to <literal>switch</literal>.
-It matches its <literal>case</literal>s based on what name currently applies to the union's value.
-As always, <literal>default</literal> matches everything.
-The following example chooses the best way to print the union:
-<informalexample><screen>
-union {
-        int a;
-        string b;
-} u;
-
-u.b = "hello";
-
-union switch ( u ) {
-        case a:
-                printf ( "%d\n", u.a );
-                break;
-        case b:
-                printf ( "%s\n", u.b );
-                break;
-}
-</screen></informalexample>
-</para>
-<para>
-In this case, it prints 'hello'.
-</para>
-<para>
-An additional name may follow that of a case; the union's value will be available inside the case by that name.
-The switch above could have been written:
-<informalexample><screen>
-union switch ( u ) {
-        case a num:
-                printf ( "%d\n", num );
-                break;
-        case b str:
-                printf ( "%s\n", str );
-                break;
-}
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Loops</title>
-<synopsis>
-while ( <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
-</synopsis>
-<synopsis>
-do <replaceable>statement</replaceable> while ( <replaceable>expr</replaceable> )
-</synopsis>
-<synopsis>
-for ( <replaceable>expr</replaceable>; <replaceable>expr</replaceable>; <replaceable>expr</replaceable> ) <replaceable>statement</replaceable>
-</synopsis>
-<para>
-<literal>while</literal> executes <replaceable>statement</replaceable> repeatedly as long as <replaceable>expr</replaceable> is true.
-Control continues outside the loop when <replaceable>expression</replaceable> becomes false.
-For example:
-<informalexample><screen>
-int x = 0;
-while ( x < 10 ) {
-        printf ( "%d\n", x );
-        ++x;
-}
-</screen></informalexample>
-</para>
-<para>
-This prints the numbers from zero to nine.
-</para>
-<para>
-<literal>do-while</literal> is like <literal>while</literal>, but tests the condition after each iteration rather than before.
-Thus, it is garaunteed to execute at least once.
-It is often used in input while testing for end-of-file:
-<informalexample><screen>
-file f = File::open ( "test", "r" );
-
-do {
-        printf ( "%s\n", File::fgets ( f ) );
-} while ( ! end ( f ) );
-
-close ( f );
-</screen></informalexample>
-</para>
-<para>
-<literal>for</literal> begins by evaluating the first <replaceable>expr</replaceable>, which often initializes a counter variable; since declarations are expressions in Nickle, they may be used here and the counter will be local to the loop.
-Then it executes <replaceable>statement</replaceable> as long as the second <replaceable>expr</replaceable> is true, like <literal>while</literal>.
-After each iteration, the third <replaceable>expr</replaceable> is evaluated, which usually increments or decrements the counter variable.
-The <literal>while</literal> example above can also be written as the following <literal>for</literal> loop:
-<informalexample><screen>
-for ( int x = 0; x < 10; ++x )
-        printf ( "%d\n", x );
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Flow control</title>
-<synopsis>
-continue
-</synopsis>
-<synopsis>
-break
-</synopsis>
-<synopsis>
-return <replaceable>expr</replaceable>
-</synopsis>
-<para>
-<literal>continue</literal> restarts the nearest surrounding <literal>do-while</literal>, <literal>while</literal>, or <literal>for</literal> loop by jumping directly to the conditional test.
-The iterative statement of a <literal>for</literal> loop will be evaluated first.
-</para>
-<para>
-<literal>break</literal> leaves the nearest surrounding <literal>do-while</literal>, <literal>while</literal>, <literal>for</literal>, or <literal>switch</literal> statement by jumping to its end.
-The iterative statement of a <literal>for</literal> loop will not be evaluated.
-</para>
-<para>
-<literal>return</literal> returns from the nearest surrounding function with value <replaceable>expr</replaceable>.
-</para>
-</sect2>
-
-</sect1>
diff --git a/doc/tutorial/intro/variables.sgml b/doc/tutorial/intro/variables.adoc
similarity index 51%
rename from doc/tutorial/intro/variables.sgml
rename to doc/tutorial/intro/variables.adoc
index add93f2..2f09fd7 100644
--- a/doc/tutorial/intro/variables.sgml
+++ b/doc/tutorial/intro/variables.adoc
@@ -1,46 +1,48 @@
-<sect1><title>Nickle Datatypes</title>
 
-<sect2><title>Primitive datatypes</title>
-<para>
+= Nickle Datatypes
+
+== Primitive datatypes
+
 Nickle has a large set of primitive datatypes.
 Instead of overloading existing datatypes to represent fundamentally distinct objects, Nickle provides additional primitive datatypes to allow for typechecking.
-For instance, instead of using small integers to identify file handles, Nickle provides a <literal>file</literal> datatype.
-</para>
-
-<sect3><title>Numeric datatypes</title>
-<para>
-Nickle has three numeric datatypes:
-</para>
-<itemizedlist>
-<listitem><para><literal>int</literal></para></listitem>
-<listitem><para><literal>rational</literal></para></listitem>
-<listitem><para><literal>real</literal></para></listitem>
-</itemizedlist>
-<para>
+For instance, instead of using small integers to identify file handles, Nickle provides a `file` datatype. 
+
+=== Numeric datatypes
+
+Nickle has three numeric datatypes: 
+
+* `int`
+* `rational`
+* `real`
+
 Int and rational values are represented exactly to arbitrary precision so that computations need not be concerned about values out of range or a loss of precision during computation.
-For example,
-<informalexample><screen>
+For example, 
+
+----
+
 > 1/3 + 2/3 == 1
 true
 > 1000! + 1 > 1000!
 true
-</screen></informalexample>
-</para>
-<para>
+----
+
 As rationals are a superset of the integers, rational values with denominator of 1 are represented as ints.
-The builtin <literal>is_int</literal> demonstrates this by recognizing such rationals as integers:
-<informalexample><screen>
+The builtin `is_int` demonstrates this by recognizing such rationals as integers: 
+
+----
+
 > rational r = 1/3;
 > is_int(r)   
 false
 > is_int(r*3)
 true
-</screen></informalexample>
-</para>
-<para>
+----
+
 Real values are either represented as a precise int or rational value or as an imprecise value using a floating point representation with arbitrary precision mantissa and exponent values.
-Imprecision is a contagious property; computation among precise and imprecise values yields an imprecise result.
-<informalexample><screen>
+Imprecision is a contagious property; computation among precise and imprecise values yields an imprecise result. 
+
+----
+
 > real i=3/4, j=sqrt(2);
 > is_rational(i)
 true
@@ -48,82 +50,80 @@ true
 false
 > is_rational(i*j)
 false
-</screen></informalexample>
-</para>
-<para>
+----
+
 Upward type conversion is handled automatically; divide an int by and int and the result is rational.
-Downward conversion only occurs through builtin functions which convert rational or real values to integers.
-<informalexample><screen>
+Downward conversion only occurs through builtin functions which convert rational or real values to integers. 
+
+----
+
 > int i=4, j=2;
 > is_rational(i/j)
 true
-</screen></informalexample>
-</para>
-</sect3>
+----
 
-<sect3><title>String datatype</title>
-<para>
-A <literal>string</literal> holds a read-only null-terminated list of characters.
+=== String datatype
+
+A `string` holds a read-only null-terminated list of characters.
 Several builtin functions accept and return this datatype.
 Elements of a string are accessible as integers by using the array index operators.
-See the section on Strings.
-<informalexample><screen>
+See the section on Strings. 
+
+----
+
 string foo = "hello";
 string bar = "world";
 string msg = foo + ", " + bar;
 
 printf("%s\n", msg);            /* hello, world */
-</screen></informalexample>
-</para>
-</sect3>
+----
+
+=== File datatype
 
-<sect3><title>File datatype</title>
-<para>
-The <literal>file</literal> datatype provides access to the native file system.
+The `file` datatype provides access to the native file system.
 Several builtin functions accept and return this datatype.
-See the section on input and output.
-<informalexample><screen>
+See the section on input and output. 
+
+----
+
 file f = open("file", "w");
 File::fprintf(f, "hello, world!\n");
 close(f);
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Concurrency and control flow datatypes</title>
-<para>
-Nickle has builtin support for threading, mutual exclusion, and continuations, along with the associated types:
-</para>
-<itemizedlist>
-<listitem><para><literal>thread</literal></para></listitem>
-<listitem><para><literal>mutex</literal></para></listitem>
-<listitem><para><literal>semaphore</literal></para></listitem>
-<listitem><para><literal>continuation</literal></para></listitem>
-</itemizedlist>
-<para>
-Threads are created with the <literal>fork</literal> expression, the result of which is a thread value.
+----
+
+=== Concurrency and control flow datatypes
+
+Nickle has builtin support for threading, mutual exclusion, and continuations, along with the associated types: 
+
+* `thread`
+* `mutex`
+* `semaphore`
+* `continuation`
+
+Threads are created with the `fork` expression, the result of which is a thread value.
 Mutexes and semaphores are synchronization datatypes.
-See the section on Concurrency and Continuations.
-<informalexample><screen>
+See the section on Concurrency and Continuations. 
+
+----
+
 thread t = fork 5!;
 # do stuf...
 printf("5! = %d\n", join(t));   /* 5! = 120 */
-</screen></informalexample>
-</para>
-<para>
-Continuations capture the dynamic state of execution in much the same way as a C <literal>jmp_buf</literal> except that the <literal>longjmp</literal> operation is not limited to being invoked from a nested function invocation.
-Rather, it can be invoked at any time causing execution to resume from the point of <literal>setjmp</literal>.
-See the section on Continuations.
-</para>
-</sect3>
-
-<sect3><title>Poly datatype</title>
-<para>
+----
+
+Continuations capture the dynamic state of execution in much the same way as a C `jmp_buf` except that the `longjmp` operation is not limited to being invoked from a nested function invocation.
+Rather, it can be invoked at any time causing execution to resume from the point of ``setjmp``.
+See the section on Continuations. 
+
+=== Poly datatype
+
 Non-polymorphic typechecking is occasionally insufficient to describe the semantics of an application.
-Nickle provides an 'escape hatch' through the <literal>poly</literal> datatype.
+Nickle provides an 'escape hatch' through the `poly` datatype.
 Every value is compatible with poly; a variable with this type can be used in any circumstance.
-Nickle performs full run-time typechecking on poly datatypes to ensure that the program doesn't violate the type rules.
-<informalexample><screen><![CDATA[
+Nickle performs full run-time typechecking on poly datatypes to ensure that the program doesn't violate the type rules. 
+
+----
+
 > poly i=3, s="hello\n";
 > i+3
 6
@@ -139,41 +139,35 @@ Unhandled exception "invalid_argument" at <stdin>:47
         "Incompatible argument"
 > printf(s)
 hello
-> 
-]]></screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Void datatype</title>
-<para>
-To handle functions with no return value and other times when the value of an object isn't relevant, Nickle includes the <literal>void</literal> datatype.
-This is designed to operate in much the same way as the <literal>unit</literal> type does in ML.
-Void is a type that is compatible with only one value, '<>'.
-This value can be assigned and passed just like any other value, but it is not type compatible with any type other than void and poly.
-</para>
-</sect3>
-
-</sect2>
-
-<sect2><title>Composite datatypes</title>
-<para>
-Nickle allows the basic datatypes to be combined in several ways.
-</para>
-<itemizedlist>
-<listitem><para><literal>struct</literal></para></listitem>
-<listitem><para><literal>union</literal></para></listitem>
-<listitem><para>arrays</para></listitem>
-<listitem><para>pointers</para></listitem>
-<listitem><para>references</para></listitem>
-<listitem><para>functions</para></listitem>
-</itemizedlist>
-
-<sect3><title>Structs</title>
-<para>
+>
+----
+
+=== Void datatype
+
+To handle functions with no return value and other times when the value of an object isn't relevant, Nickle includes the `void` datatype.
+This is designed to operate in much the same way as the `unit` type does in ML.
+Void is a type that is compatible with only one value, '<>'. This value can be assigned and passed just like any other value, but it is not type compatible with any type other than void and poly. 
+
+== Composite datatypes
+
+Nickle allows the basic datatypes to be combined in several ways. 
+
+* `struct`
+* `union`
+* arrays
+* pointers
+* references
+* functions
+
+
+=== Structs
+
 Structs work much like C structs; they composite several datatypes into an aggregate with names for each element of the structure.
 One unusual feature is that a struct value is compatible with a struct type if the struct value contains all of the entries in the type.
-For example:
-<informalexample><screen>
+For example: 
+
+----
+
 typedef struct {
         int     i;
         real    r;
@@ -188,23 +182,21 @@ i_and_r i_and_r_value = { i = 12, r = 37 };
 just_i  i_value;
 
 i_value = i_and_r_value;
-</screen></informalexample>
-</para>
-<para>
-The assignment is legal because <literal>i_and_r</literal> contains all of the elements of <literal>just_i</literal>.
-<literal>i_value</literal> will end up with both <literal>i</literal> and <literal>r</literal> values.
-</para>
-</sect3>
-
-<sect3><title>Unions</title>
-<para>
+----
+
+The assignment is legal because `i_and_r` contains all of the elements of ``just_i``. ``i_value`` will end up with both `i` and `r` values. 
+
+=== Unions
+
 Unions provide a way to hold several different datatypes in the same object.
 Unions are declared and used much like structs.
 When a union element is referenced, Nickle checks to make sure the referring element tag is the one currently stored in the union.
 This provides typechecking at runtime for this kind of polymorphism.
 Values can be converted to a union type by specifying a compatible union tag cast.
-A control structure <literal>union switch</literal> exists to split out the different tags and perform different functions based on the current tag:  
-<informalexample><screen>
+A control structure `union switch` exists to split out the different tags and perform different functions based on the current tag: 
+
+----
+
 typedef union {
         int     i;
         real    r;
@@ -225,85 +217,70 @@ case r:
 
 u_value = (i_and_r_union.r) 1.2;
 printf ("u_value %g\n", u_value);               /* u_value r = 1.2 */
-</screen></informalexample>
-</para>
-</sect3>
-
-<sect3><title>Arrays</title>
-<para>
-Array types in Nickle determine only the number of dimensions and not the
-size of each dimension. Therefore they can be declared in one of three ways:
-<informalexample><screen>
+----
+
+=== Arrays
+
+Array types in Nickle determine only the number of dimensions and not the size of each dimension.
+Therefore they can be declared in one of three ways: 
+
+----
+
 int[*] a;
 int[...] b;
 int[3] c;
-</screen></informalexample>
-</para>
-<para>
-By these declarations, <literal>a</literal>, <literal>b</literal> and
-<literal>c</literal> are of the same type (one-dimensional array).
-The specification of the size of <literal>c</literal> actually has no effect
-on its declaration but rather on its initialization.  See Initialization
-below.  Declaring multidimensional arrays in Nickle is different than in C;
-C provides only arrays of arrays while Nickle allows either:
-<informalexample><screen>
+----
+
+By these declarations, ``a``, `b` and ``c`` are of the same type (one-dimensional array). The specification of the size of `c` actually has no effect on its declaration but rather on its initialization.
+See Initialization below.
+Declaring multidimensional arrays in Nickle is different than in C; C provides only arrays of arrays while Nickle allows either: 
+
+----
+
 int[3,3]        array_2d = {};
 int[3][3]       array_of_arrays = { (int[3]) {} ... };
 
 array_2d[0,0] = 7;
 array_of_arrays[0][0] = 7;
 array_of_arrays[1] = (int[2]) { 1, 2 };
+----
+
+These two types can be used in similar circumstances, but the first ensures that the resulting objects are rectangular while the second allows for each row of the array to have a different number of elements.
+The second also allows for each row to be manipulated separately.
+The final example shows an entire row being replaced with new contents. 
+
+Array values created with '...' in place of the dimension information are resizable; requests to store beyond the bounds of such arrays will cause the array dimensions to be increased to include the specified location.
+Resizable arrays may also be passed to the `setdim` and ``setdims`` built-in functions. 
+
+=== Hashes
+
+Hashes provide an associative mapping from arbitrary keys to values.
+Any type may be used as the key.
+This allows indexing by strings, and even composite values.
+They are called ``hashes`` instead of associative arrays to make the performance characteristics of the underlying implementation clear. 
+
+Hashes are declared a bit like arrays, but instead of a value in the brackets, a type is placed: 
+
+----
 
-</screen></informalexample>
-</para>
-<para>
-These two types can be used in similar circumstances, but the first ensures
-that the resulting objects are rectangular while the second allows for each
-row of the array to have a different number of elements.  The second also
-allows for each row to be manipulated separately.  The final example shows
-an entire row being replaced with new contents.
-</para>
-<para>
-Array values created with '...' in place of the dimension information are
-resizable; requests to store beyond the bounds of such arrays will cause
-the array dimensions to be increased to include the specified location.
-Resizable arrays may also be passed to the <literal>setdim</literal> and
-<literal>setdims</literal> built-in functions.
-</para>
-</sect3>
-<sect3><title>Hashes</title>
-<para>
-Hashes provide an associative mapping from arbitrary keys
-to values. Any type may be used as the key.  This allows indexing by
-strings, and even composite values.  They are called
-<literal>hashes</literal> instead of associative arrays to make the
-performance characteristics of the underlying implementation clear.
-</para>
-<para>
-Hashes are declared a bit like arrays, but instead of a value in the
-brackets, a type is placed:
-<informalexample><screen>
 int[string]     string_to_int = { "hello" => 2, => 0 };
 float[float]    float_to_float = { 2.5 => 27 };
 
 string_to_int["bar"] = 17;
 string_to_int["foo"] += 12;
 float_to_float[pi] = pi/2;
+----
+
+The initializer syntax uses the double-arrow `=>` to separate key from value.
+Eliding the key specifies the "default" value -- used to instantiate newly created elements in the hash. 
+
+=== Pointers
 
-</screen></informalexample>
-</para>
-<para>
-The initializer syntax uses the double-arrow <literal>=></literal> to
-separate key from value.  Eliding the key specifies the
-"default" value -- used to instantiate newly created elements in the hash.
-</para>
-
-</sect3>
-<sect3><title>Pointers</title>
-<para>
 Pointers hold a reference to a separate object; multiple pointers may point at the same object and changes to the referenced object are reflected both in the underlying object as well as in any other references to the same object.
-While pointers can be used to point at existing storage locations, anonymous locations can be created with the reference built-in function; this allows for the creation of pointers to existing values without requiring that the value be stored in a named object.
-<informalexample><screen><![CDATA[
+While pointers can be used to point at existing storage locations, anonymous locations can be created with the reference built-in function; this allows for the creation of pointers to existing values without requiring that the value be stored in a named object. 
+
+----
+
 *int    pointer;
 int     object;
 
@@ -316,35 +293,38 @@ pointer = reference (37);
 (*pointer)++;
 
 printf ("%g\n", *pointer);              /* 38 */
-]]></screen></informalexample>
-</para>
-</sect3>
+----
+
+=== References
 
-<sect3><title>References</title>
-<para>
 References, like pointers, refer to objects.
 They are unlike pointers, however; they are designed to provide for calls by reference in a completely by-value language.
 They may eventually replace pointers altogether.
-They are declared and assigned similarly, but not identically, to pointers:
-<informalexample><screen><![CDATA[
+They are declared and assigned similarly, but not identically, to pointers: 
+
+----
+
 &int ref;
 int  i;
 
 i = 3;
 &ref = &i;
-]]></screen></informalexample>
-<literal>ref</literal> is declared as a reference to an integer, <literal>&int</literal>.
-An integer, <literal>i</literal>, is declared and given the value 3.
-Finally, the assignment carries some interesting semantics: the address of the reference is set to the address of <literal>i</literal>.
-References may also be assigned otherwise anonymous values with <literal>reference</literal>, e.g.
-<informalexample><screen><![CDATA[
+----
+====``ref`` is declared as a reference to an integer, ``&int``.
+An integer, ``i``, is declared and given the value 3.
+Finally, the assignment carries some interesting semantics: the address of the reference is set to the address of ``i``.
+References may also be assigned otherwise anonymous values with ``reference``, e.g. 
+
+----
+
 &int foo;
 &foo = reference ( 3 );
-]]></screen></informalexample>
+----
 References, unlike pointers, need not be dereferenced; they are used exactly as any other value.
-Changing either the value it refers to or the reference itself changes both.
-</para>
-<informalexample><screen>
+Changing either the value it refers to or the reference itself changes both. 
+
+----
+
 printf("%g\n", i);      /* 3 */
 printf("%g\n", ref);    /* 3 */
 
@@ -352,17 +332,19 @@ printf("%g\n", ref);    /* 3 */
 
 printf("%g\n", i);      /* 4 */
 printf("%g\n", ref);    /* 4 */
-</screen></informalexample>
-</sect3>
+----
+
+=== Functions
 
-<sect3><title>Functions</title>
-<para>
-Nickle has first-class functions.  These look a lot like function pointers in C, but important semantic differences separate the two.
+Nickle has first-class functions.
+These look a lot like function pointers in C, but important semantic differences separate the two.
 Of course, if you want a function pointer in Nickle, those are also available.
 Function types always have a return type and zero or more argument types.
 Functions may use the void return type.
-The final argument type may be followed by an elipsis (...), in which case the function can take any number of arguments at that point, each of the same type as the final argument type:
-<informalexample><screen>
+The final argument type may be followed by an elipsis (...), in which case the function can take any number of arguments at that point, each of the same type as the final argument type: 
+
+----
+
 int(int, int)   a;
 void(int ...)   b;
 
@@ -370,34 +352,22 @@ a(1,2);
 b(1);
 b(1,2);
 b(1,"hello");   /* illegal, "hello" is not compatible with int */
-</screen></informalexample>
-</para>
-<para>
-See the section on Functions.
-</para>
-</sect3>
+----
+
+See the section on Functions. 
 
-</sect2>
+== Declarations
 
-<sect2><title>Declarations</title>
-<para>
 A declaration in Nickle consists of four elements: publication, storage class, type, and name.
-Publication, class, and type are all optional but at least one must be present and they must be in that order.
-</para>
-<itemizedlist>
-<listitem><para>
-Publication is one of public or protected, which defines the name's visibility within its namespace.
-When publication is missing, Nickle uses <literal>private</literal> meaning that the name will not be visible outside of the current namespace.
-See the section on Namespaces.
-</para></listitem>
-<listitem><para>
-Class is one of global, static, or auto.
-When class is missing, Nickle uses <literal>auto</literal> for variables declared within a function and <literal>global</literal> for variables declared at the top level.
-See Storage classes below.
-</para></listitem>
-<listitem><para>
-Type is some type as described here, for instance
-<informalexample><screen><![CDATA[
+Publication, class, and type are all optional but at least one must be present and they must be in that order. 
+
+* Publication is one of public or protected, which defines the name's visibility within its namespace. When publication is missing, Nickle uses `private` meaning that the name will not be visible outside of the current namespace. See the section on Namespaces. 
+* Class is one of global, static, or auto. When class is missing, Nickle uses `auto` for variables declared within a function and `global` for variables declared at the top level. See Storage classes below. 
+* Type is some type as described here, for instance 
++
+
+----
+
 type                    /* primitive type */
 *type                   /* pointer to type */
 &type                   /* reference to type */
@@ -408,20 +378,19 @@ struct { ... }          /* struct of types */
 union { ... }           /* union of types */
 type(type,...)[*]       /* array of functions */
 /* etc. */
-]]></screen></informalexample>
-</para>
-<para>
+----
++
 When type is missing, Nickle uses poly, which allows the variable to hold data of any type.
-In any case, type is always checked at runtime.
-</para></listitem>
-</itemizedlist>
-</sect2>
+In any case, type is always checked at runtime. 
+
+
+== Initializers
 
-<sect2><title>Initializers</title>
-<para>
 Initializers in Nickle are expressions evaluated when the storage for a variable comes into scope.
-To initialize array and structure types, expressions which evaluate to a struct or array object are used:
-<informalexample><screen>
+To initialize array and structure types, expressions which evaluate to a struct or array object are used: 
+
+----
+
 int     k = 12;
 int     z = floor (pi * 27);
 int[3]  a = (int[3]) { 1, 2, 3 };
@@ -432,80 +401,77 @@ typedef struct {
 } i_and_r;
 
 i_and_r s = (i_and_r) { i = 12, r = pi/2 };
-</screen></informalexample>
-</para>
-<para>
-As a special case, initializers for struct and array variables may elide the type leaving only the bracketed initializer:
-<informalexample><screen>
+----
+
+As a special case, initializers for struct and array variables may elide the type leaving only the bracketed initializer: 
+
+----
+
 int[3]  a = { 1, 2, 3 };
 i_and_r s = { i = 12, r = pi/2 };
-</screen></informalexample>
-</para>
-<para>
+----
+
 Instead of initializing structures by their position in the declared type, Nickle uses the structure tags.
-This avoids common mistakes when the structure type is redeclared.
-</para>
-<para>
-An arrays initializer followed by an elipsis (...) is replicated to fill the remainder of the elements in that dimension:
-<informalexample><screen>
+This avoids common mistakes when the structure type is redeclared. 
+
+An arrays initializer followed by an elipsis (...) is replicated to fill the remainder of the elements in that dimension: 
+
+----
+
 int[4,4]        a = { { 1, 2 ... }, { 3, 4 ... } ... };
-</screen></informalexample>
-</para>
-<para>
-This leaves <literal>a</literal> initialized to an array who's first row is <literal>{ 1, 2, 2, 2 }</literal> and subsequent rows are <literal>{ 3, 4, 4, 4 }</literal>.
+----
+
+This leaves `a` initialized to an array who's first row is `{ 1, 2, 2, 2 }` and subsequent rows are ``{ 3, 4, 4, 4 }``.
 It is an error to use this elipsis notation when the associated type specification contains stars instead of expressions for the dimensions of the array.
 Variables need not be completely initialized; arrays can be partially filled and structures may have only a subset of their elements initialized.
-Using an uninitialized variable causes a run time exception to be raised.
-</para>
-</sect2>
-
-<sect2><title>Identifier scope</title>
-<para>
-Identifiers are scoped lexically; any identifier in lexical scope can be used in any expression (with one exception described below).
-Each compound statement creates a new lexical scope.
+Using an uninitialized variable causes a run time exception to be raised. 
+
+== Identifier scope
+
+Identifiers are scoped lexically; any identifier in lexical scope can be used in any expression (with one exception described below). Each compound statement creates a new lexical scope.
 Function declarations and statement blocks also create new lexical scopes.
-This limits the scope of variables in situations like:
-<informalexample><screen>
+This limits the scope of variables in situations like: 
+
+----
+
 if (int i = foo(x))
         printf ("i in scope here %d\n", i);
 else
         printf ("i still in scope here %d\n", i);
 printf ("i not in scope here\n");
-</screen></informalexample>
-</para>
-<para>
-Identifiers are lexically scoped even when functions are nested:
-<informalexample><screen>
+----
+
+Identifiers are lexically scoped even when functions are nested: 
+
+----
+
 function foo (int x) {
         int y = 1;
         function bar (int z) { return z + y; }
         return bar (x);
 }
-</screen></informalexample>
-</para>
-</sect2>
-
-<sect2><title>Storage classes</title>
-<para>
-There are three storage classes in Nickle:
-</para>
-<itemizedlist>
-<listitem><para>auto</para></listitem>
-<listitem><para>static</para></listitem>
-<listitem><para>global</para></listitem>
-</itemizedlist>
-<para>
+----
+
+== Storage classes
+
+There are three storage classes in Nickle: 
+
+* auto
+* static
+* global
+
 The storage class of a variable defines the lifetime of the storage referenced by the variable.
-When the storage for a variable is allocated, any associated initializer expression is evaluated and the value assigned to the variable.
-</para>
+When the storage for a variable is allocated, any associated initializer expression is evaluated and the value assigned to the variable. 
+
+=== Auto variables
 
-<sect3><title>Auto variables</title>
-<para>
 Auto variables have lifetime equal to the dynamic scope where they are defined.
 When a function is invoked, storage is allocated which the variables reference.
 Successive invocations allocate new storage.
-Storage captured and passed out of the function will remain accessible.
-<informalexample><screen><![CDATA[
+Storage captured and passed out of the function will remain accessible. 
+
+----
+
 *int function foo (int x)
 {
         return &x;
@@ -513,18 +479,17 @@ Storage captured and passed out of the function will remain accessible.
 
 *int    a1 = foo (1);
 *int    a2 = foo (2);
-]]></screen></informalexample>
-</para>
-<para>
-<literal>a1</literal> and <literal>a2</literal> now refer to separately allocated storage.
-</para>
-</sect3>
-
-<sect3><title>Static variables</title>
-<para>
+----
+
+`a1` and `a2` now refer to separately allocated storage. 
+
+=== Static variables
+
 Static variables have lifetime equal to the scope in which the function they are declared in is evaluated.
-A function value includes both the executable code and the storage for any enclosed static variables, function values are created from function declarations.
-<informalexample><screen>
+A function value includes both the executable code and the storage for any enclosed static variables, function values are created from function declarations. 
+
+----
+
 int() function incrementer ()
 {
         return (func () { 
@@ -535,15 +500,16 @@ int() function incrementer ()
 
 int()   a = incrementer();
 int()   b = incrementer();
-</screen></informalexample>
-</para>
-<para>
-<literal>a</literal> and <literal>b</literal> refer to functions with separate static state and so the values they return form independent sequences.
+----
+
+`a` and `b` refer to functions with separate static state and so the values they return form independent sequences.
 Because static variables are initialized as the function is evaluated and not during function execution, any auto variables declared within the enclosing function are not accessible.
 This is the exception to the lexical scoping rules mentioned above.
 It is an error to reference auto variables in this context.
-Additionally, any auto variables declared within an initializer for a static variable exist in the frame for the static initializer, not for the function.
-<informalexample><screen><![CDATA[
+Additionally, any auto variables declared within an initializer for a static variable exist in the frame for the static initializer, not for the function. 
+
+----
+
 function foo ()
 {
         static function bar (*int z)
@@ -554,19 +520,18 @@ function foo ()
 
         return x;
 }
-]]></screen></informalexample>
-</para>
-<para>
-The static initializer is an anonymous function sharing the same static scope as the function containing the static declarations, but having its own unique dynamic scope.
-</para>
-</sect3>
-
-<sect3><title>Global variables</title>
-<para>
+----
+
+The static initializer is an anonymous function sharing the same static scope as the function containing the static declarations, but having its own unique dynamic scope. 
+
+=== Global variables
+
 Global variables have lifetime equal to the global scope.
 When declared at global scope, storage is allocated and the initializer executed as soon as the declaration is parsed.
-When declared within a function, storage is allocated when the function is parsed and the initializer is executed in the static initializer of the outermost enclosing function.
-<informalexample><screen>
+When declared within a function, storage is allocated when the function is parsed and the initializer is executed in the static initializer of the outermost enclosing function. 
+
+----
+
 function foo ()
 {
         function bar ()
@@ -580,14 +545,7 @@ function foo ()
         }
         return bar ();
 }
-</screen></informalexample>
-</para>
-<para>
-Because <literal>g</literal> has global scope, only a single instance exists and so the returned values from <literal>foo</literal> increment each time <literal>foo</literal> is called.
-However, because <literal>s</literal> has static scope, it is reinitialized each time <literal>bar</literal> is reevaluated as the static initializer is invoked and returns the same value each time <literal>foo</literal> is called.
-</para>
-</sect3>
-
-</sect2>
+----
 
-</sect1>
+Because `g` has global scope, only a single instance exists and so the returned values from `foo` increment each time `foo` is called.
+However, because `s` has static scope, it is reinitialized each time `bar` is reevaluated as the static initializer is invoked and returns the same value each time `foo` is called. 
\ No newline at end of file
diff --git a/doc/tutorial/nickle-tutorial.adoc b/doc/tutorial/nickle-tutorial.adoc
new file mode 100644
index 0000000..a85d774
--- /dev/null
+++ b/doc/tutorial/nickle-tutorial.adoc
@@ -0,0 +1,79 @@
+= Nickle Tutorial
+Robert Burgess; Keith Packard
+:doctype: book
+:sectnums:
+:toc: left
+:icons: font
+:experimental:
+
+== Nickle Tour
+
+The following is an example Nickle session, interspersed with comments. 
+
+:leveloffset: 2
+
+include::tour/tour.adoc[]
+
+:leveloffset: 0
+
+== Nickle Basics
+
+Nickle is a powerful desktop calculator language with many features of
+advanced languages and support for arbitrary precision numbers.  It
+can run interactively to fulfill its role as a calculator, evaluate
+single expressions, and execute Nickle scripts.  It also has an array
+of useful top-level commands for interacting with the interpreter.
+
+:leveloffset: 2
+
+include::basics/invoke.adoc[]
+include::basics/command.adoc[]
+
+:leveloffset: 0
+
+== Language introduction
+
+In this chapter, the features of Nickle such as datatypes,
+expressions, control statements, and functions will be discussed.  By
+the end, most of the basic language features will have been covered.
+
+:leveloffset: 2
+
+include::intro/variables.adoc[]
+include::intro/expressions.adoc[]
+include::intro/statements.adoc[]
+include::intro/functions.adoc[]
+
+:leveloffset: 0
+
+== Builtins
+
+This chapter will explain various important builtin functions of
+Nickle, such as those for input and output and math.  It will also
+discuss the various operators and builtin functions that manipulate
+strings.
+
+:leveloffset: 2
+
+include::builtins/io.adoc[]
+include::builtins/math.adoc[]
+include::builtins/strings.adoc[]
+
+:leveloffset: 0
+
+== Advanced topics
+
+This chapter will discuss more advanced topics; these features make
+Nickle as powerful as it is.  The semantics of copying and garbage
+collection, namespaces, exceptions, threading and mutual exclusion,
+and continuations will all be covered.
+
+:leveloffset: 2
+
+include::advanced/copying.adoc[]
+include::advanced/namespaces.adoc[]
+include::advanced/exceptions.adoc[]
+include::advanced/concurrency.adoc[]
+include::advanced/continuations.adoc[]
+
+:leveloffset: 0
diff --git a/doc/tutorial/nickle-tutorial.sgml b/doc/tutorial/nickle-tutorial.sgml
deleted file mode 100644
index 6d5d708..0000000
--- a/doc/tutorial/nickle-tutorial.sgml
+++ /dev/null
@@ -1,115 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-<!ENTITY tour SYSTEM "tour/tour.sgml">
-
-<!ENTITY invoke SYSTEM "basics/invoke.sgml">
-<!ENTITY command SYSTEM "basics/command.sgml">
-
-<!ENTITY variables SYSTEM "intro/variables.sgml">
-<!ENTITY expressions SYSTEM "intro/expressions.sgml">
-<!ENTITY statements SYSTEM "intro/statements.sgml">
-<!ENTITY functions SYSTEM "intro/functions.sgml">
-
-<!ENTITY io SYSTEM "builtins/io.sgml">
-<!ENTITY math SYSTEM "builtins/math.sgml">
-<!ENTITY strings SYSTEM "builtins/strings.sgml">
-
-<!ENTITY copying SYSTEM "advanced/copying.sgml">
-<!ENTITY namespaces SYSTEM "advanced/namespaces.sgml">
-<!ENTITY exceptions SYSTEM "advanced/exceptions.sgml">
-<!ENTITY concurrency SYSTEM "advanced/concurrency.sgml">
-<!ENTITY continuations SYSTEM "advanced/continuations.sgml">
-]>
-
-<book>
-
-<bookinfo>
-
-<title>Nickle Tutorial</title>
-
-<authorgroup>
-
-<author>
-<firstname>Robert</firstname>
-<surname>Burgess</surname>
-</author>
-
-<author>
-<firstname>Keith</firstname>
-<surname>Packard</surname>
-</author>
-
-</authorgroup>
-
-<abstract>
-<para>
-This is a user tutorial for Nickle, a powerful desktop
-calculator language. Nickle supports many features of
-advanced languages, as well as arbitrary precision numbers.
-This tutorial is intended to teach Nickle to someone who is already fairly familiar with programming, using descriptions with examples.
-Topics are covered progressively, beginning with invocation and commands, moving on to learning the language, and finally to more advanced topics.
-</para>
-</abstract>
-
-</bookinfo>
-
-<chapter><title>Nickle Tour</title>
-<abstract>
-<para>
-The following is an example Nickle session, interspersed with comments.
-</para>
-</abstract>
-&tour;
-</chapter>
-
-<chapter><title>Nickle Basics</title>
-<abstract>
-<para>
-Nickle is a powerful desktop calculator language with many features of advanced languages and support for arbitrary precision numbers.
-It can run interactively to fulfill its role as a calculator, evaluate single expressions, and execute Nickle scripts.
-It also has an array of useful top-level commands for interacting with the interpreter.
-</para>
-</abstract>
-&invoke;
-&command;
-</chapter>
-
-<chapter><title>Language introduction</title>
-<abstract>
-<para>
-In this chapter, the features of Nickle such as datatypes, expressions, control statements, and functions will be discussed.
-By the end, most of the basic language features will have been covered.
-</para>
-</abstract>
-&variables;
-&expressions;
-&statements;
-&functions;
-</chapter>
-
-<chapter><title>Builtins</title>
-<abstract>
-<para>
-This chapter will explain various important builtin functions of Nickle, such as those for input and output and math.
-It will also discuss the various operators and builtin functions that manipulate strings.
-</para>
-</abstract>
-&io;
-&math;
-&strings;
-</chapter>
-
-<chapter><title>Advanced topics</title>
-<abstract>
-<para>
-This chapter will discuss more advanced topics; these features make Nickle as powerful as it is.
-The semantics of copying and garbage collection, namespaces, exceptions, threading and mutual exclusion, and continuations will all be covered.
-</para>
-</abstract>
-©ing;
-&namespaces;
-&exceptions;
-&concurrency;
-&continuations;
-</chapter>
-
-</book>
diff --git a/doc/tutorial/tour/tour.sgml b/doc/tutorial/tour/tour.adoc
similarity index 69%
rename from doc/tutorial/tour/tour.sgml
rename to doc/tutorial/tour/tour.adoc
index 61c3309..a92cb0f 100644
--- a/doc/tutorial/tour/tour.sgml
+++ b/doc/tutorial/tour/tour.adoc
@@ -1,32 +1,36 @@
-<para>
-<screen>
+
+
+----
+
 $ nickle
-</screen>
-Arithmetic works as expected, with a rich set of operators.
-<screen>
+----
+Arithmetic works as expected, with a rich set of operators. 
+----
+
 > 1 + 1
 2
 > 2 ** (2 + 2)
 16
 > 5!
 120
-</screen>
+----
 Rationals are represented exactly, but printed in decimal.
 Math is done with infinite precision.
-Notice that integer division (//) is different from rational division (/).
-Nickle provides some conveniences, such as <literal>.</literal> denoting the last value printed.
-<screen>
+Notice that integer division (//) is different from rational division (/). Nickle provides some conveniences, such as `$$.$$` denoting the last value printed. 
+----
+
 > 1 / 3
 0.{3}
 > . * 3
 1
 > 1 // 3
 0
-</screen>
+----
 Variables can be declared implicitly at the top level, as well as explicitly with type.
 The results of statements are not printed; terminating an expression with a semicolon makes it a simple statement.
-C-like control structures may also be used at the top level; the <literal>+</literal> prompt indicates an incomplete line to be continued.
-<screen><![CDATA[
+C-like control structures may also be used at the top level; the `\+` prompt indicates an incomplete line to be continued. 
+----
+
 > x = .
 0
 > int y = x;
@@ -39,11 +43,12 @@ C-like control structures may also be used at the top level; the <literal>+</lit
 +   x += i;
 > x
 16
-]]></screen>
+----
 When performing square roots, Nickle will stay exact when possible.
 If the result is irrational, however, it will be stored as an inexact real.
-Imprecision is contagious; if a rational operator combines an imprecise variable with a precise one, the result will be imprecise.
-<screen>
+Imprecision is contagious; if a rational operator combines an imprecise variable with a precise one, the result will be imprecise. 
+----
+
 > sqrt(x)
 4
 > sqrt(2)
@@ -56,10 +61,11 @@ Imprecision is contagious; if a rational operator combines an imprecise variable
 4.999999999999999
 > . / 5
 0.999999999999999
-</screen>
+----
 Functions can also be typed at the top level.
-Since functions, as most things, are first-class in Nickle, they may be declared and assigned as below.
-<screen>
+Since functions, as most things, are first-class in Nickle, they may be declared and assigned as below. 
+----
+
 > real foo(real x, real y) {
 +   return x * y;
 + }
@@ -70,33 +76,30 @@ Since functions, as most things, are first-class in Nickle, they may be declared
 > real(real, real) bar = foo;
 > bar(4, 2)
 8
-> 
-</screen>
+>
+----
 Nickle is guaranteed never to dump core; it has a simple yet powerful exception system it uses to handle all errors.
-An unhandled exception leads to the debugger, which uses a <literal>-</literal> prompt.
-The debugger can be used to trace the stack, move up and down on it, and check values of variables.
-<screen>
+An unhandled exception leads to the debugger, which uses a `-` prompt.
+The debugger can be used to trace the stack, move up and down on it, and check values of variables. 
+----
+
 > (-1) ** (1/2)
 Unhandled exception invalid_argument ("sqrt of negative number", 0, -1)
 /usr/share/nickle/math.5c:19:     raise invalid_argument ("sqrt of negative number", 0, v);
     sqrt (-1)
 /usr/share/nickle/math.5c:895:     result = sqrt (a);
     pow (-1, 0.5)
-<stdin>:1:     -1 ** (1 / 2);
+<stdin>:1:     -1 ** (1 / 2);
 - done
 > quit
 $
-</screen>
-Large chunks of code can be placed in a separate text file
-and loaded when needed.  The <literal>print</literal>
-command can be used to inspect variables, functions,
-namespaces, and other names.
-<literal>import</literal> brings the names in a namespace
-into scope.  The <literal>::</literal> operator can be used
-to view those names without importing them.  (These can also
-be used with several namespaces built in to Nickle, such as
-Math and File.)
-<screen>
+----
+Large chunks of code can be placed in a separate text file and loaded when needed.
+The `print` command can be used to inspect variables, functions, namespaces, and other names. ``import`` brings the names in a namespace into scope.
+The `::` operator can be used to view those names without importing them.
+(These can also be used with several namespaces built in to Nickle, such as Math and File.) 
+----
+
 $ nickle
 > load "cribbage.5c"
 > print Cribbage
@@ -108,7 +111,7 @@ namespace Cribbage {
 public void handprint (int[*] hand)
 {
     printf ("hand { ");
-    for (int i = 0; i < dim (hand); ++i)
+    for (int i = 0; i  dim (hand); ++i)
         switch (hand[i]) {
         case 1:
             printf ("A ");
@@ -132,6 +135,5 @@ public void handprint (int[*] hand)
 > handprint(hand); printf(" has %d points.\n", scorehand(hand));
 hand { 7 8 Q 10 5 }  has 6 points.
 > quit
-$ 
-</screen>
-</para>
+$
+----
\ No newline at end of file
commit 4aa795ad12a83d60ce0dd57f98e72b001d4218ef
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Sep 1 16:56:06 2020 -0700

    Version 2.87
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index 53b5c5c..ac6070d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,8 +6,8 @@ dnl for licensing information.
 
 AC_PREREQ([2.69])
 
-AC_INIT([nickle],[2.86],[http://nickle.org],[nickle])
-RELEASE_DATE="2020-04-17"
+AC_INIT([nickle],[2.87],[http://nickle.org],[nickle])
+RELEASE_DATE="2020-09-01"
 AC_CONFIG_SRCDIR([nickle.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR(.)
diff --git a/debian/changelog b/debian/changelog
index 1d61eaa..2a9594d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+nickle (2.87) unstable; urgency=medium
+
+  * Don't install Makefile and Makefile.in. Closes: #958110.
+  * pow(0,0) = 1
+
+ -- Keith Packard <keithp at keithp.com>  Sat, 18 Apr 2020 16:12:15 -0700
+
 nickle (2.86) unstable; urgency=medium
 
   * Fix exp() of small values. They were rounding to zero
commit cd4fecefb1829a9ddebe373c20b6f5a03901fddb
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Sep 1 16:55:40 2020 -0700

    Don't install Makefile and Makefile.in
    
    Why were these ever installed?
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/debian/rules b/debian/rules
index 314cb55..a453e87 100755
--- a/debian/rules
+++ b/debian/rules
@@ -20,3 +20,11 @@ export DH_VERBOSE=1
 override_dh_auto_install:
 	dh_auto_install && (find debian/nickle -name COPYING -print0 | xargs -0 rm)
 	find debian/nickle/usr/share/nickle -type f -print0 | xargs -0 grep -l '^#!.*nickle' | xargs -d '\n' chmod +x
+
+
+# These files are generated. Makefile includes absolute paths which
+# makes it not work on end-user machines, and cause the build to be
+# not reproducible.
+
+override_dh_installdocs:
+	dh_installdocs -XMakefile -XMakefile.in
commit 42b57f9a46f81b6ca3f4443888261d44391babf4
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Sep 1 16:55:01 2020 -0700

    Adjust Makefile.am for native debian package
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/Makefile.am b/Makefile.am
index 997ed67..410320b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -93,7 +93,7 @@ builtin.o main.o: Makefile
 
 TARFILE=$(PACKAGE)-$(VERSION).tar.gz
 SIGFILE=$(PACKAGE)-$(VERSION).tar.gz.asc
-DEBFILE=$(PACKAGE)_$(VERSION)-1_amd64.deb
+DEBFILE=$(PACKAGE)_$(VERSION)_amd64.deb
 SRPMFILE=$(RPMDIR)/SRPMS/$(PACKAGE)-$(VERSION)-1.src.rpm
 RPMFILE=$(RPMDIR)/RPMS/$(PACKAGE)-$(VERSION)-1.x86_64.rpm
 RELEASE_FILES = $(TARFILE) $(SIGFILE) $(DEBFILE) $(SRPMFILE) $(RPMFILE)
commit 729564a5aa782117d74030294fbadc398c169163
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Sep 1 16:53:54 2020 -0700

    Make pow compatible with C — pow(0,0) = 1
    
    There is no good answer, so pick one that matches C at least.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/math.5c b/math.5c
index 77b6608..ec86bfa 100644
--- a/math.5c
+++ b/math.5c
@@ -971,8 +971,11 @@ extend namespace Math {
 	 */
     {
 	real    result;
-	if (a == 0)
+	if (a == 0) {
+	    if (b == 0)
+		return 1;
 	    return 0;
+	}
 
 	if (is_int (b))
 	{


More information about the Nickle mailing list