runtime: String scanning improvements

This should approximately double the speed of substring operations on
non-ASCII strings.

- Add support for scanning backwards from the end of the string instead
  of forward from the passed starting point. On average this will halve
  the number of bytes needed to be scanned. However, for operations like
  slicing off the last character of a string this will be a significant
  improvement

- When scanning a range in a non-ASCII string we can still use our ASCII
  optimisation for the end pointer if the start pointer is past all the
  Unicode characters. This replaces an asciiOnly() check with a test if
  the number of remaining bytes in the string equal the number of
  remaining characters.
stdlib: Implement (number->string)

- Add defaultRadix argument to DatumWriter::render(). This only affects
  the top-level datum being written

- Add base 2, 8 and 16 support to renderExactInteger()

- Implement (number->string) on top of ExternalFormDatumWriter
Add <eof-object> as distinct type

(read) needs to return an eof-object when it encounters an end-of-file.
This means it cannot be any datum that can be read using (read).
Currently <eof-object> is an alias for <unit> which can be represented
as #!unit

For the same reason there is no reader form for <eof-object>. It can
only be obtained using (eof-object).
runtime: Add stub DatumReader

This is the counterpart to DatumWriter. It is intended to support
reading datums from an input stream, and eventually implement the (read)
library.

Currently it will only return an <eof-object> for any input without
reading anything. It is only used by an simple runtime unit test.
compiler: Explicitly test #d prefix

Decimal numbers can optionally be prefixed by #d or #D. We supported
this but it was never explicitly tested.
stdlib: Implement (string->number)

This is built on a very restricted implementation of DatumReader that
can only parse numbers and booleans. However, within those limitations
it should parse all of the number forms that the Scala parser supports
including:

- Binary, octal, decimal and hex exact integers

- Decimal and fractional real numbers

- Special values (+inf.0, -inf.0, +nan.0)