An initial implementation of source mappings.
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.
Showing with 1941 additions and 299 deletions