When consuming source code from a stream, the compiler now optionally
collects the start and end position of each list the reader reads
(atoms aren't tracked - see below), threads this information all the
way through to the printer, and associates it with the start and end
positions of the corresponding JS being generated.
Note that this is an expression-based way of doing source maps as
opposed to the line-based approach of the Google/Mozilla source map
spec. This is a much richer and Lispier way to do it. But converting
to the line-based format will require tracking lines in the printer.
That work is not part of this commit.
Text extents of forms are tracked in a big EQ-hash-table of which the
forms themselves are the keys. This has the disadvantage that atomic
tokens such as variable names don't get their source mappings tracked
(though see note  below). It has the much greater advantage of
making the source mapping implementation not be too invasive. I tried
the alternative implementation of consing the text extents as metadata
onto the heads of each cons to be compiled. This worked, but had the
consequence that any compiler code that needs to pick apart the forms
it is given must be aware of this optional (because source mappings
may be turned off) metadata at the head - and, Lisp being what it is,
"compiler code" here includes any PS macros that anybody writes. That
is far too heavy a burden to place on macros even if the PS compiler
itself could stand it. Storing the metadata on the side avoids this;
now only those portions of the compiler that care about preserving the
source mappings of the forms they are given need worry about them, and
for any forms they are passing on untransformed they can just ignore
this extra information. Similarly, macros that wish to propagate
source mappings have the option of doing so, but also have the option
of remaining blissfully ignorant.
 Tricks could be applied to work around this. For example, atoms
that appear inside conses could be uniquely identified using the cons
plus an integer index. But this would be a lot more work, both to
develop and more importantly at runtime, and it's not clear whether
the more precise mappings would be worth it.