On Mon, Feb 2, 2015 at 2:06 PM, Ron Buckton
wrote:
> > 1. When the compiler needs to embed a runtime with various helper
> > functions in the generated JS code. In this case, I think it makes sense
> to add
> > an entry to the sources list and map the appropriate code to this runtime
> > source.
>
> Is there a general best-practice for this? Traceur adds an entry to the
> 'sources' list that is prefixed with "@traceur/generated", as well as
> adding an entry to 'sourcesContent' containing the same text written to the
> generated output file. Adding a string to sourceContent for this purpose
> seems like unnecessary overhead. TypeScript emits null mappings for each
> line of generated content.
>
It depends on whether you want to step through the runtime source in
debuggers. If you do, then embed the runtime as a source in the sourcemap
like Traceur does. If you don't want to step through your runtime's source,
then use null mappings and debuggers should step through it.
If you're concerned about sending the runtime source over the wire twice
(once in the generated JS code and once embedded in the source map) then
you can load the runtime as a separate script in debug builds. I don't have
any other great answers.
>
> > 2. When a single statement in the source language results in many
> > statements in the JS code. In this case, I believe that all the generated
> > statements in the JS code should map back to the same location in the
> source
> > language. When implementing source level single stepping, debuggers
> > should continue JS object code level single stepping until the source map
> > reports a new source location for the current JS code. This is
> conceptually the
> > same as when single stepping C-source level statements in gdb/lldb/etc
> that
> > map to multiple asm instructions: you don't want to pause after executing
> > each asm instruction, but once all the asm instructions for that C
> statement
> > have been executed.
>
> While this makes sense for statements that generate a sequential set of
> steps, it breaks down slightly when you are generating something like the
> downlevel emit for a generator or async function, where you might end up
> with something like this:
>
> ```TypeScript
> async function asyncFunc(p: Promise): Promise {
> console.log("before");
> var i = await p;
> console.log("after");
> return i;
> }
> ```
>
> Which generates (with the current Async Functions prototype, plus
> additional comments):
> ```js
> var __awaiter = ...; // runtime helper
> var __generator = ...; // runtime helper
> function asyncFunc(p) {
> // (a)
> return new Promise(function(_resolve) {
> _resolve(__awaiter(__generator(function(_state) {
> // (b)
> switch (_state) {
> // (c)
> case 0:
> // (d)
> console.log("before");
> return [4 /*yield*/, p];
> // (e)
> case 1:
> // (f)
> i = _state.sent;
> console.log("after");
> return [2 /*return*/, i + 1];
> }
> });
> });
> var i;
> }
> ```
>
> When the debugger steps through 'asyncFunc', it will execute [a], [b],
> [c], and [d] immediately before yielding, and when the state machine is
> resumed it will execute [b], [c], [e], and [f]. As a result, [b] and [c]
> are executed twice (and for a larger function body with multiple 'case'
> clauses, it would likely step through each case clause up to the current
> "label"). Based on my understanding of your response below, we should emit
> "null" mappings for [a]-[c] and for [e]. When the debugger steps into the
> function for the first time it should step through until it hits [d], and
> after it resumes it should step through until it hits [f]. Is this an
> accurate assumption?
>
This sounds correct to me.
|
|