Skip to content
This repository

line number mapping for debug #558

Closed
pmuellr opened this Issue July 30, 2010 · 180 comments
Patrick Mueller

There's been some email chit-chat regarding support coffeescript in the existing browser debuggers. The basic idea is to include information in the generated JavaScript files that the debuggers can make use of to display the original coffeescript source, and deal with line mapping issues between the CoffeeScript source and generated JavaScript.

Thought I'd go ahead and open up an issue for discussion.

Patrick Mueller

So some thoughts:

  • CoffeeScript source location - somehow we need the coffeescript source. See Issue #557 as one possible solution. The debugger would then be responsible for finding the source given that "URL". Java current just uses the basename() of the file as the file name in it's debug info, but of course it also has the full class name available to it as well. Not sure how we might get some "relative" name in there, so it seems like basename() or abspath() of the input file are the choices. abspath() exposes more information than it should, basename() will cause naming conflicts for same-named files in different directories

  • line number information - The debugger will eventually want this in hash tables, both directions. Go from a cs line # to js line # when setting breakpoints, and js line # to cs line # when the JS vm is communicating to the debugger (eg, "stopped at line 47"). Presumably the actual data for the line number data could be in JSON format (eg, an object literal mapping cs #'s to an array of js #'s).

mrblonde

Might be worth looking at this also:
http://nex-3.com/posts/92-firesass-bridges-the-gap-between-sass-and-firebug

Maybe this same type of strategy could be used so that firebug could step through javascript line by line, but display the coffeescript code instead.

Tough project, but could turn into something pretty killer!

Jeremy Ashkenas
Owner

I'd be glad to help someone out with this ticket, but I'm not going to be spearheading it myself ... so closing as frozen for the time being. If someone wants to step up and do a port of FireSass for CoffeeScript, do let us know.

Jeremy Ashkenas
Owner

Alright -- this ticket now has life again, in Firefox at least:

https://bugzilla.mozilla.org/show_bug.cgi?id=618650

Reopening...

Thomas Aylott

Quick helpful workaround:

Include each line of the original coffeescript source inside a block comment before the js code that it generated. You could include the original coffeescript source lune numbers in the comments.

That would at least help simplify the learning and debugging process.

Stan Angeloff

Mascara has a source-line mapping utility that only works in Firefox. It's quite possible to implement something similar:

try
  console.log 'Hello'
  a for i in [0..10]
catch error
  lines = { 31: 3, 32: 3, 33: 3 }
  error.message = error.message + ' on line ' + lines[error.stack.split('\n').shift().split(':').pop()]
  throw error

Run on Try CoffeeScript. Firefox only, though.

Andrew Schaaf

Related code:

Closure Compiler (JS -> JS)

...can generate source-to-source mappings:

java -jar $CLOSURE_JAR --js example.js --create_source_map ./map --js_output_file compiled.js

SourceMapLegacy.java has comments describing the format.

PYXC-PJ (PY -> JS)

...can generate mappings using the same format, but with more file info: [{"sha1":"...",...}] instead of []

commit: "changed emit() return type from a string to list of strings and kids"

commit: "source-to-source mappings! (same format as Closure Compiler)"

** exception-server **

An exception logging/viewing server has been written (in NodeJS) that uses these mappings to convert an exception's stack information into pre-compilation code snippets with TextMate URLs.

(your compilers/scripts send the server (code_sha1, mapping)s and (sha1, code)s at compile-time)

I'll post it [REDACTED TIMEFRAME] when it's more documented/polished.

** common-exception **

...can extract file/line/[col] information from NodeJS, Firefox, Chrome, Safari

lucaswoj

Crazy idea: What if when the CoffeeScript was compiled to JavaScript, it was done such that the lines corresponded 1:1 by placing multi-line JavaScript conversions on a single line.

Patrick Mueller

I suspect it is crazy, but it would be useful. I actually do that with https://github.com/pmuellr/scooj , but only because the source is largely unprocessed JavaScript anyway. The nice thing is that even though you see some grungy code in the debugger, you do know the exact line number to go to in your editor.

Alexander Trefz

I suggest a --debug coffee parameter that does something like this:

# Add Core-Utils to Underscore Namespace
_.ducktype = (obj, methods...) ->
  some("code")

to become:

var __slice = Array.prototype.slice;
// Line 2
_.ducktype = function() {
  var methods, obj;
  obj = arguments[0], methods = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  // Line 3
  return some("code");
};

this would work Browser independent and i think(im not a coffescript compiler expert, though) it could be implement without big hassles.

Andrew Schaaf

Let's define some terms:

Def a "compiler" compiles a non-empty set of "source file"s to exactly one "compiled file"

Defs

  • a "(coord to coord)-mapping" is a function from (line, col) in the compiled file to (source_file_ref, line, col)

  • a "(line to line)-mapping" is a function from (line) in the compiled file to (source_file_ref, line)

  • a compiled file is "{coord,line}-{coord,line}-commented" if it contains comments in some format which provide a ({coord,line} to {coord,line})-mapping

  • a "(...mapping...) file" is a byte-string in some format which contains a representation of a (...mapping...)

Notes:

  • Don't worry, the representations of these mappings are usually much more space-efficient than the ultra-trivial {coord1:info1, ...}
  • source_file_ref should include sha1(source_file) if possible, because that's really useful when used with my not-yet-released exception server

Defs

  • "CCMF" is a (coord to coord)-mapping format. It's what Closure Compiler generates
  • "CCMFH" is a backward-compatible extension with required hashes and optional other info

See my writeup of CCMF[H]: https://gist.github.com/769845

Andrew Schaaf

.lineno

Recall: adding .lineno to each node instance is a solved problem:

#955

With no side effects, that grammar.coffee change could be merged at any time.

Andrew Schaaf

Let's get this done! (Please? Please? Please?)

CoffeeScript should support both

  1. {coord,line}-line-commenting in whatever that format turns out to be (e.g. via --line-commenting)
  2. exporting CCMFH files (e.g. via --ccmfh-out=)

(1) might need to wait for some format finalization, but (2) does not.

And the nodes.coffee work required for (2) will apply to (1).

I'm trying to do a FOSS triple-launch in [REDACTED TIMEFRAME]:

(all three are written in CoffeeScript)

...and it would be really, really awesome to have CoffeeScript CCMFH support before then so I can integrate it.

Imagine being able to hit Command-R and have jashkenas/coffee-script-tmbundle compile, invoke node, and then represent the resulting exception in a beautiful and convenient mapping-following way with CoffeeScript source links and code snippets...

Andrew Schaaf

Some modest proposals

The Good (but more complex and possibly slower)

Something like what PYXC-PJ does.

EDIT: e.g.

Throw
  compileNode: (o) ->
    ...
    something(o, ["throw ", @expression, ";"])

Instead of having the main compilation function return a string, have it return a BAR.

BAR ::= ELEMENT-list

ELEMENT ::= string | FOO | BAR

FOO ::= something which can
    1. provide the code fragment for that subtree
    2. provide the ((line, col) -> (source line))
       mapping information for that fragment

Some function can then use the resulting BAR to generate both

  1. the usual JavaScript
  2. a CCMFH file

PYXC-PJ commits:

I'm not a nodes.coffee expert (yet) so I'm not sure if subnode.compile(o) can be deferred. If so would let FOO be, e.g., {subnode:@expression, o:o}

Would o have been destructively modified by the time foo.subnode(foo.o) gets run?

I think The Good could be done without deferring .compile, but that might be harder.

The Bad (but simple (though verbose) to implement and possibly faster)

Something like what Closure Compiler does.

Instead of the beatifully concise current compileNode methods, do something like:

    something.startNode this
    something.add           "throw {"
    something.addSubnode    @expression, o
    
    # addSubnode: (node, o) ->
    #   ...
    #   node.compile o
    #   ...
    
    something.add           ";"
    something.endNode()

This would invoke the .compiles in the same order as the current implementation.

The Fugly

Have whatever methods invoke compileNode replace ([...].compileNode([...])) with

((() ->
    token = newUniqueToken()
    (
        "/*FUGLY:#{token}:@lineno*/" + 
        [...].compileNode([...]) +
        "/*/FUGLY:#{token}*/"
    )
)())

...and write a crazy function that uses the resulting text monstrosity to generate (comment-free JS, a CCMFH file)

This would be totally insane, but it would work and it would involve the least modification to nodes.coffee

Andrew Schaaf

I'll work on a

something(o, ["throw ", @expression, ";"])

approach

Andrew Schaaf

BAR-ification of nodes.coffee in progress:

https://github.com/andrewschaaf/coffee-script/commits/master

After each change, I run

git checkout -- lib && cake build && cake build && cake test && git status

and confirm that the tests pass and that no lib/*.js files other than nodes.coffee are changed

Andrew Schaaf

From #coffeescript yesterday:

my point about a codegen method's "/**/#{@child.compile o}" vs "#{@child.compile o}/**/" was that the codegen method currently discards the information distinguishing the two.

the relativeCharOffset of each kid matters.

one option would be for the codegen method to store that information in its kids

e.g. for Throw ("throw #{@expression...};"),

@expression.relativeCharOffset = "throw ".length

but this could make the codegen methods uglier than with the BAR-returning approach

with the BAR-returning approach, the Base method calling the codegen method can process the BAR immediately, computing the flattenedCodeString as usual and (processing the mapping implications if mapping:true)

BAR-returning codegen methods are a way to abstract out the mapping-handling code

from the outside, you're still calling the top node's .compile or .compileWithMapping

Andrew Schaaf

From #coffeescript yesterday:

my point about a codegen method's "/**/#{@child.compile o}" vs "#{@child.compile o}/**/" was that the codegen method currently discards the information distinguishing the two.

the relativeCharOffset of each kid matters.

one option would be for the codegen method to store that information in its kids

e.g. for Throw ("throw #{@expression...};"),

@expression.relativeCharOffset = "throw ".length

but this could make the codegen methods uglier than with the BAR-returning approach

with the BAR-returning approach, the Base method calling the codegen method can process the BAR immediately, computing the flattenedCodeString as usual and (processing the mapping implications if mapping:true)

BAR-returning codegen methods are a way to abstract out the mapping-handling code

from the outside, you're still calling the top node's .compile or .compileWithMapping

Oscar Campbell

About ten years ago I wrote som crude source-to-source compilers for Perl and C++ which I called Pyrl and Cython. They simply gave you pythonish indent-syntax. They had the flag -p for pretty output and some other for line-to-line, which esentially means that it simply made sure that lines in the output ended up in the same line number as in the input, no matter if certain lines became 'ugly' because of code stacking.

Simple solution. Works in all environments (like Jake that compiles the coffee-makefile from inside it's script), any editor, etc., shouldn't be to hard to implement?

Deleted user

The content you are editing has changed. Reload the page and try again.

How hard would it be to add an option to have the js output include a call to a custom trace function on every function call? The param could be the callee function name and optionally the original line number and file. This would really help debug those cases where the code doesn't finish because I forgot to call something else at the end of a callback. These cases drive me crazy and cause me to put log calls all over the place.

The convention could be that if a specific function exists at the top level then the feature is enabled and that function is called.

debugFnCallLog = (funcName, fileName, lineNum) ->
    myCustomLogRoutine ...
Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Mathieu Ravaux

For reference, here is a related webkit ticket: https://bugs.webkit.org/show_bug.cgi?id=30933

Deleted user
ghost commented April 19, 2011

The content you are editing has changed. Reload the page and try again.

In my fantasy world V8 and other engines would be broken into a separate parser and byte-code interpreter while retaining the same JS semantics.

Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Aseem Kishore
aseemk commented May 03, 2011

Just want to toss out a major +1 to preserving line numbers, i.e. mapping 1:1 from source Coffee line # to generated JS line #. The excellent Streamline.js library has this option for its transformations, and it has proved invaluable.

Btw, if it helps, our platform is Node. We too compile dynamically w/out generating JS files, so things like line-numbers-in-comments aren't helpful. Our use case also isn't e.g. Firebug debugging generally but more "my program threw an error on line 512, where is that?"

Thanks in advance! Excitedly looking forward to seeing what comes of this.

Alisson Cavalcante Agiani

+1 for this

Andrew Schaaf

Anyone in the NYC area interested in meeting up for a line-mapping mini-hackathon on Sunday the 15th?

lucaswoj
Tane Piper

+1 I'd send some coffee + beer money too for this, it would be the biggest evolution for CoffeeScript

Deleted user
ghost commented May 04, 2011

The content you are editing has changed. Reload the page and try again.

Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Michael Ficarra
Collaborator

I'll actually be in the NYC area on the 15th with nothing to do. I may be up for this.

lephyrius

+1 for some way of debugging coffeescript. It would be really helpful.

Andrew Schaaf

The 15th is a go. [EDIT: multiple parties cancelled.]

Possible attack plan:

  • Add .line_number to nodes (satyr's implementation involves more changes but seems cleaner and safer than this hack)
  • Create mapping files via fugly hack (see above)
  • NodeJS exception logging/viewing server (to run on localhost) with {mapping file support, code snippets, TextMate links}
  • Create mapping files properly
Oscar Campbell
ozra commented May 09, 2011

I definitely vote for line to line compiling without mapping files. Way to go! :-) If I wasn't in 'way after deadline'-mode on my current project, I'd help out right away.

Patrick Mueller
pmuellr commented May 10, 2011

This WebKit / Web Inspector bug may be of interest to folks:

Bug 60550: Web Inspector: add protocol method for loading script source mapping

Presumably for Traceur (it's from Google folks), and just describes the "protocol" by which source mappings are obtained, not the format of the source mappings of themselves.

Gerald Lewis geraldalewis referenced this issue from a commit May 15, 2011
Commit has since been removed from the repository and is no longer available.
Gerald Lewis geraldalewis referenced this issue from a commit May 15, 2011
Commit has since been removed from the repository and is no longer available.
Gerald Lewis geraldalewis referenced this issue from a commit in geraldalewis/coffee-script May 13, 2011
Gerald Lewis Debug mode for running .coffee scripts #558, #987 f31af40
Gerald Lewis

@michaelficarra and @andrewschaaf -- somehow missed you two were working on a solution to this together (today?). I got somewhere with it if it helps you! https://gist.github.com/973659
Edit: Hah! @andrewschaaf, missed everything after early May before working on this -- came to many of the same solutions you did :) Wish I'd seen it sooner!

Andrew Schaaf

@geraldalewis: Sweet!

@michaelficarra and I were too busy that day to meet up and hack. I made some progress on a line-mapping-friendly exception-server. I'll get it done and posted [redacted].

Andrew Schaaf

With this many comments on a GitHub page, we need to start posting some 9f09aeb-style lulz...

Gerald Lewis geraldalewis referenced this issue from a commit in geraldalewis/coffee-script May 26, 2011
Gerald Lewis Debug mode for running .coffee scripts #558, #987 9d0fa7c
Patrick Mueller

Web Inspector: draft implementation of compiler source mappings support in debugger:

Draft description of source maps for Web Inspector (linked to in the bug):

The actual format of the sourcemap is not yet specified, though it's presumably JSON as the bug talks about retrieving the source maps via JSONP.

The interface to be provided based on the data is not completely specified, but there's bits of it here, in the section for new source file "CompilerSourceMappings.js":

The idea is, we have the raw source map data, and then provide a JS object which matches that shape that use the data to return the expected results, and voilà! CoffeeScript debugging in Web Inspector.

treeform

pmuellr: When will that be live?

I would not mind the one-to-one idea in the mean time:
"Crazy idea: What if when the CoffeeScript was compiled to JavaScript, it was done such that the lines corresponded 1:1 by placing multi-line JavaScript conversions on a single line." - lucaswoj

Patrick Mueller

treeform: no telling when it will be "live". Work in progress. That could be committed tomorrow, say, or never. Good news is that it's being done by the GOOGlers who are the primary Web Inspector devs, so it will likely ship, sometime. Would first be available in WebKit nightlies, so might want to install that now so you can be ready the minute it makes it into the build! cc yourself on the bug, of course.

I'd rather see any work done, be in generating "source maps", whatever form that may be. It's the answer long-term, compared to the 1-1 line # story. Easy for me to say tho, since I'm not doing ANY of this work ... :-)

Patrick Mueller

It appears that the Moz and Google Closure folks are now also on the case! Here's another Source Map proposal linked to in WebKit bug 63940.

Andrew Schaaf

Speaking of formats, here's what Closure Compiler uses now:

https://gist.github.com/1082926#file_foo.simple.js.mapping

(it's a newer format than what they were using earlier in this thread...)

Nick Fitzgerald

Hello! I am a summer intern for Mozilla acting as the lead on the source map project. The source map project will allow mapping any X to JS compilation's line/col/source location info including among others CoffeeScript to JS and JS to Minified JS as long as there exists a source map file. Here's a quick overview of the project status:

Now I'd like to begin working source map generation in to CoffeeScript. I'll take a look at previous patches and see if I can't reuse a bunch of that code.

So yeah, I just wanted to say hello and publicly announce my intents.

Michael Blume

@fitzgen: awesome. I'm sure I'm not the only one here who's hugely excited about this ^_^

Michael Ficarra
Collaborator

@fitzgen: from the source map proposal:

Additional fields may be added to the top level source map provided the fields begin with the “x_” naming convention.

That sounds like a really bad design decision. Why not nest objects under some extensions property?

edit: Sorry, I meant to bring this up a few weeks ago, but I couldn't add comments to the google document, so I just kind of forgot about it.

Pete Nicholls

@fitzgen Awesome!

I agree with @michaelficarra – an extensions property seems a better choice here.

Alexander Trefz

+1 for @michealficarra's idea.

Nick Fitzgerald fitzgen referenced this issue from a commit in fitzgen/coffee-script August 17, 2011
Nick Fitzgerald issue #558 part 1 - Adding line and column information to the nodes i…
…n the AST

so that data isn't lost after parsing, and we can use it to generate source
maps.
7592664
showell

What is the status on adding lines/columns to the Node objects?

Nick Fitzgerald

@showell, The commit above should maintain the line/col info in the AST after parsing is finished. Unfortunately, I haven't finished the second half where I actually use that information to generate source maps. I have a bunch of dirty stuff that needs to be revisited and probably rethought, but at the moment I am preoccupied with other things.

Patrick Mueller

We'll also need a VLQ library, to read/write integers.

There was also some discussion in webkit bug 60969 concerning
how Web Inspector will retrieve the sourcemap files. There are options:

  • JSONP via script injection
  • JSON via CORS (claims that it won't work though)
  • IFRAME html wrapper that access the files

We may need to be generate JSONP wrappers for the sourcemap/source, or an extra .html file, or something.

Nick Fitzgerald

@pmuellr, the spec already defines how a source map should be fetched, see "Linking generated code to source maps" in https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1

Also, my core source map lib, which is meant to be used by Firefox internals, compilers and minifiers, developer tools, etc already handles the VLQ stuff as well as actually generating and consuming source maps as long as you can pass it the information required.

https://github.com/mozilla/source-map

Basically, all that needs to happen to make CoffeeScript generate source maps is to replace all the string interpolation and concatenation with building a tree of SourceNodes which are part of that core library above. Each mapping in a source map needs the original line/col, original source, and generated line/col. Using the SourceNodes just allows us to maintain the original line/col/source info while building up snippets of generated JS. Then when the tree is complete, we can do an in order traversal of the tree as we concatenate the snippets, and by doing this we will always know the generated line/col for a given location while we concatenate and we will have all the info we need.

Little bit of a brain dump, if it doesn't make sense I can try and clarify.

Patrick Mueller

All the spec mentions w/r/t "Linking generated code to source maps" is how to "link" to the source map in the generated source. It doesn't specify, nor should it, how a debug agent actually GETs those files, once it has the links. If you were implementing a debugger as a plain old html app (say, like weinre or running Web Inspector in "remote" mode) how would you go about actually GETting the files? That's the nub of the issue. Presumably you'd use XHR or whatever. Then you may have cross-origin issues. Etc. Again, see webkit bug 60969 for a discussion of the techniques being considered.

This is a rubber-meeting-the-road issue. How do we actually hook this all up and make it work?

Happy to see the https://github.com/mozilla/source-map stuff. Except it's MPL/GPL/LGPL so some folks will have issues. Like the coffee-script project. :-1:

How are folks supposed to contribute to the "discussion" in the referenced Google Doc? Is the discussion happening in the doc, or somewhere else, and if it's in the doc, how do I get r/w access to it? This isn't a great place to discuss this stuff.

Elliot Winkler

So is Google talking about adding support for Source Map (or something similar) to v8? This would help out when using CoffeeScript within node.js.

showell

I am asking for this one-line patch to be accepted for src/grammar.coffee:

-  [patternString, "$$ = #{action};", options]
+  [patternString, "$$ = (function(){ var _ = #{action}; _.lineno = yylineno; return _; })()", options]

I totally understand that browsers are still working out line mappings, but this patch has applicability that extends beyond those use cases, and I can't imagine a more minimal patch.

Michael Ficarra
Collaborator

@showell: open a pull request with some use cases.

update: the next series of comments will seem out of place, since @showell has deleted his comments

Jeremy Ashkenas
Owner

Yep, a minimally-invasive way to get line numbers in to the AST would be great.

Michael Ficarra
Collaborator

@showell:

  • it gives us a place to discuss it -- now and in the future when someone asks about it
  • it makes it easier for us to merge
  • we can see it in the proper context
  • why bitch about it when it's a means for you to get what you want?
Gerald Lewis

@showell -- that line looks like it's from my patch in #1396 :

[patternString, "$$ = (function(){ var _ = #{action}; if(typeof _.lineno !== 'undefined'){_.lineno = yylineno; }; return _; })()", options]

(No idea why I chose _ instead of a descriptive name, but that tags each node with its line number within Jison.)

I'm not sure if that line can be made more elegant, though I hope so. The cleanest solution would be a patch for Jison, but that creates new problems. I prefer this approach over modifying the grammar (the strategy that @fitzgen employed in 7592664 and @satyr uses in coco). Modifying the grammar to include numbers feels creaky and conflates grammar with metadata unnecessarily.

I think you'll still need to elucidate your use cases as @michaelficarra suggested :)

Satoshi Murakami
Collaborator

Note that:

  • yylineno refers to the last token in the rule, so attaching it blindly can screw up.
  • creating 200-ish IIFEs within one switch has certain overhead.
  • we'll have to adopt @fitzgen's approach for source mapping eventually.
Michael Ficarra
Collaborator

@showell: In English, "bitch" used in that context is not a derogatory term. It means "to whine or complain". I was asking why you would rather complain about opening a pull request than just do it and have us formally consider it. Pull requests are a nice standard practice with many benefits that I listed above. For some reason, you (and a few others like you that I've interacted with here on github) would rather attack me in a knee-jerk reaction than consider the fact that you're interpreting my words incorrectly. I was just trying to help you.

  • the "patch" you submitted would be a lot easier to merge with one simple click of github's merge button
  • its proper forum would be an issue (pull request) dedicated to it
  • again, it would be helpful to evaluate the patch when given the context in the pull request
  • our compiler doesn't need to add line number information to the AST; it works perfectly fine without it
    • yes, it would be more interoperable
    • but I also couldn't care less about it now that I see you don't really care about how the other people that work on the project are treated

edit: minor wording/punctuation

Michael Ficarra
Collaborator

@showell:

  • Yes, it's a very similar amount of work, but only once we've already determined that it
    1. is one of our goals (it probably would be)
    2. implements it the way we want (very unsure)
    3. performs well and generates nice output
    4. a whole laundry list of other approval conditions
  • This isn't the proper forum; this issue is about line number mapping: it's pretty much about source maps now
  • I meant the context around that line of code. We can make more informed decisions when that's just presented to us.
  • I'm not calling for inaction. All I requested is that you create a dedicated place to continue discussion of your proposal. It wasn't unreasonable. It would have taken you only a few minutes. That's why I questioned you complaining about it. It made it seem like you didn't really care that much.
Satoshi Murakami
Collaborator

@satyr Can you elaborate on making yylineno more precise?

You can't really make it any more precise--the logic is hard-coded into the Jison generated parser.

good to know the edge cases

e.g. https://github.com/jashkenas/coffee-script/blob/1.1.2/src/grammar.coffee#L492

Can you elaborate on your other points as well?

  • The rules are compiled into one big switch statement.
    • See parser.js.
    • Try cake bench (for perf) and cake build:browser (for size).
  • yylineno will be unused when adopting source mapping (as we'll need column numbers as well). See @fitzgen's patch.
Satoshi Murakami
Collaborator

If you are arguing that my patch is harmful, I'll put up more of a fight, but I'll defer to reason

As always, I'm:

  • merely pointing out the patch's implications.
  • not the one to decide. It's up to Jeremy.
Pete Nicholls

Chill

Guys, can you please chill out? At time of writing there's 24 people subscribed to this issue, many of whom are probably getting email notifications like me. I don't know about you, but I could sure use less internet-grade arguments in my mailbox. This isn't the place for a personal spat.

Can we please get over who's "right" or who "started it", open a new pull request, and forget about the whole thing?

Can we just move on with our lives?

showell

Sincere apologies for my stupid comments. I went back and deleted a bunch of them, so I apologize if I have now put some other's folks comments out of context.

This is the proposed patch:

-  [patternString, "$$ = #{action};", options]
+  [patternString, "$$ = (function(){ var _ = #{action}; _.lineno = yylineno; return _; })()", options]

It's mostly a small excerpt from a more recent patch from @geradlewis. It tags each node with its line number within Jison. Perhaps a more descriptive name than "_" could be used. I will open a new pull request soon.

Nick Fitzgerald

Happy to see the https://github.com/mozilla/source-map stuff. Except it's MPL/GPL/LGPL so some folks will have issues. Like the coffee-script project. :-1:

When writing that lib I just used the conventional Mozilla tri-license without really thinking. I've opened up a bug to get it re-licensed to BSD so that it is easier to include in projects like CoffeeScript: https://bugzilla.mozilla.org/show_bug.cgi?id=692281

Andrew Schaaf

Anyone in NYC (and globally) up for a #558-and-related-tools hackfest all day Saturday Nov 26?

http://www.meetup.com/nodejs/events/39626642/

sevifives

I haven't been able to read through all this, but couldn't a debug mode just output a comment line of the CS code that's being converted to JS right before the conversion?

//math =
math = {
//root: Math.sqrt
root: Math.sqrt,
//square: square
square: square,
//cube: (x) -> x * square x
cube: function(x) {
return x * square(x);
}
}

Sure... it'll probably double your JS size... but it's a debug.

showell

@sevifives Your suggestion seems pragmatic, but the root causes of CS not having line numbers are twofold:

  1. All the patches that have been submitted have either been ignored or deemed too complex. In fairness to Jeremy, he's a busy guy, and there are indeed bigger fish to fry.
  2. The current main-branch implementation discards line numbers at the lexing stage. When you discard line numbers at the lexing stage, even your seemingly pragmatic suggestion becomes difficult.

I have a fork of CS that implements line numbers:

showell/coffee-script@4961119

I haven't bothered to package up the pull request yet, because it doesn't seem to be a high priority, but the code is there for the taking.

So far my patch only goes as far as passing line numbers to the Node instances, and you can get line numbers in the --nodes output. It would be a fairly simple matter to extend my patch write a source code mapping. At least one other person has already done this, but his patch was a little messy in its strategy for passing line numbers into the node objects.

There is nothing technically difficult about providing line number support in a transcompilation language; it's just a weakness of the current implementation.

Andrew Schaaf

It's not just about debug mode.

It's important to be able to go from a browser-side exception stacktrace and have your exception logging/viewing system follow the line maps for Closure Compiler minification, then coffeescript, then coffeesurgeon bodystitch-ing or connect-assets snocket-ing all the way back to specific positions in your repo's specific commit's .coffee coffee files.

Join the hackfest and get your #558 on! 3 RSVPs so far.

Andrew Schaaf

#558 hackfest update:

The date is now Saturday, December 10th.

The page is now under the CoffeeScript New York meetup.

http://www.meetup.com/Coffee-Script-New-York/events/41391392/

See you there!

showell

See also: 1918

showell

@andrewschaaf and others, I have written up some notes that might help folks get up to speed on line number support:

https://gist.github.com/1452964

My approach is hacky, but it requires very minimal code changes, so it might be useful for a warmup spike in the hackfest.

I wrote it up as a gist, instead of a patch, because some of the code is basically scaffolding, but if you go to the "showell" branch of coffee-script, there's a working version that includes all the changes from the gist.

Elliot Winkler

@showell: Oof. That is really non-trivial, isn't it...

Andrew Schaaf

@jimtla and I have proof-of-concepts for all of the above except ugly -> (js, map): https://github.com/jfdi

Jeremy Ashkenas
Owner

Hey line-number troopers.

I just got an email update from @fitzgen on the current state of Source Maps in Firefox, and I hope he doesn't mind if I share part of it with y'all here:

Unfortunately, I think the work has slowed down a bit. [...] The state of
things where I left them was that there were a few things that depended
on the new JS debugger API which has been in the works for some
time now, and that my source map work couldn't land until that code
was finished. You can look at the dependency graph between all the
bugs and perhaps get a better idea of what I am talking about:
https://bugzilla.mozilla.org/showdependencygraph.cgi?id=670002

I expect that the patch to the webconsole which is attached to bug
670002 needs to be updated as well because the webconsole wasn't
e10s (seperate processes for chrome and content) compliant at the
time that I wrote the patch, and I believe it is now.

To sum things up, I think there is a little bit of plumbing left to do
between the debugger and the webconsole's source map integration,
as well as checking patches for bit rot. The biggest thing is the new
debugger features that the source map integration relies on, and I am
not sure when they will be ready to land.

Elliot Winkler

Guys, I realize that most people probably use CoffeeScript in the browser, but waiting until Firefox supports Source Maps isn't very satisfactory to me. 1) Everyone I know uses Chrome for development and 2) Source Maps wouldn't do anything for people who are running CS against node.js. I appreciate everyone's work on this, but it seems like trying to come up with a complete solution (e.g. @andrewschaaf's three-fold strategy) isn't completely necessary, at first. I know this question has been asked before, but is it not possible to simply tag the generated JS with line numbers? This would get 90% of the way there for people who simply want a way to map JS back to CS. The other 10%, such as mapping minified JS to unminified JS -- that sounds pretty neat, but consider the fact that no JS compiler has this capability at the moment, so no one is clamoring that this particular problem be solved. You know?

Jeremy Ashkenas
Owner

@mcmire: You're right. Waiting for browsers tends to be a fool's game ;)

Tagging the generated JS with line numbers may be wise -- since this ticket was first opened, lack of line numbers has become the favorite whipping boy of folks looking for a reason to ignore CoffeeScript. Even if we don't tend to use it, perhaps --line-numbers would make for a nice compiler option.

Andrew Schaaf

Hackfest summary:

We need to get the second 80% (tests, visualization tools, correctness...) done some other weekend. Jan 7, perhaps?

--line-numbers would be nice, and it would get line numbers into the AST on master.

"no JS compiler has this capability at the moment"

"no one is clamoring that this particular problem be solved"

And 1800s focus groups would have found that people wanted faster horses.

Tane Piper

"no one is clamoring that this particular problem be solved"

26 on this thread, and it's probably one of the most common complaints I hear about CoffeeScript

showell

@jashkenas @mcmire @andrewschaaf @tanepiper Apologies in advance that this is mostly +1 to what already has been said, but, yep, I totally agree with a couple ideas that have been expressed recently on this thread.

  1. Line number support is a major sticking point for CS adoption. Most of the stick-to-JS rants you see on the web are kind of silly, but they almost all mention debugging as a sore point, and it's impossible to refute their current concerns, even if they exaggerate the difficulty and/or ignore the inevitability of progress.
  2. We can add plenty of debugging improvements to CS that have nothing to do with browser source maps. I actually write as much CS on the server side as in the browser. Even for browser code, some kind of line number annotation would make debugging easier, even before any support comes from the browser inspectors.

I've poked around with line number support, and here are the decision points that I see as important:

  1. External source map or annotated JS? Simply annotating the JS has a certain simplicity, but I think an external source map is ultimately more flexible, so that third party tools don't have to wade through the generated JS to get line number mappings, and so that the JS itself stays small.
  2. Parser cleanup? There have already been a few patches submitted for line number support, and they have tended to be fairly invasive. Part of the problem is that there's not a one-to-one relationship between grammar elements and AST nodes. There are good reasons that this is the case, but the impedance mismatch makes it challenging to patch in line number support without a lot of special cases.
  3. Roadmap? If we simply attached line numbers to the AST objects, then third party tools could access the line numbers even without a special command-line option. This would be a great start, but it wouldn't help actual debugging until JS line numbers were married to the CS line numbers. It would, on the other hand, allow for tools like linters and visualizers to be written.

The biggest sticking point is probably the parsing roadmap. If there is any intention to rearchitect grammar.coffee, then that should happen before any serious line number efforts. I know @michaelficarra has ideas in this regard, and I suspect @satyr would have insight as well. Has anybody been watching this project?: https://github.com/fab13n/parsec-coffee-script

Patrick Mueller

The Chrome/WebKit/Web Inspector folks are also working on SourceMaps, as well as the FIrefox folks. I don't know what the current status is though.

+1 on --line-numbers:

  • it will shut people up, a little
  • it will force the mapping of original line # to generated source into the CS translator (assuming it's not already there), which will be nice infrastructure to have in place once real SourceMap (or whatever) support comes along

I'll also note that I don't believe there is any SourceMap support working anywhere, for anything, in the browsers. It isn't fully baked. Who knows, maybe it'll never work. I wouldn't suggest start working on actual SourceMap support until one of the browser vendors show it working on something - a dumb minizer or something.

Rob Tsuk

I've started work on a patch to provide source maps (or line numbers, once you can do the first the second is easy)

branch: https://github.com/rtsuk/coffee-script/tree/rwt-sourcemap

plan: https://github.com/rtsuk/coffee-script/wiki/Source-Map-Plan

progress: https://gist.github.com/1508440

I think I've got the hard parts figured out and should have something to ring in the new year. Advice on approach and style are very welcome.

showell

Here is the o() function in grammar.coffee in the version from @rtsuk:

o = (patternString, action, options) ->
  patternString = patternString.replace /\s{2,}/g, ' '
  return [patternString, '$$ = $1;', options] unless action
  action = if match = unwrap.exec action then match[1] else "(#{action}())"
  action = action.replace /\bnew /g, '$&yy.'
  action = action.replace /\$L\(([\w_$]+)\)/g, 'new yy.Location(@$1)'
  action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
  [patternString, "$$ = #{action};", options]

Once line number support is thrown in, you see this idiom over and over again further down in the file:

-> new Literal($1).setLocation($L(1))

This could probably be DRY'ed up by allowing o() to distinguish strings from functions.

For complicated constructions, you'd still use the functions:

new Value($1, [].concat $2).setLocation($L(1))

Then o() does its current magic.

But for simple constructs you could simplify the DSL:

"Literal $1"

If o() detects a string, it could build the equivalent of whatever '-> new Literal($1).setLocation($L(1))' expands to.

I hope this makes sense. Long story short, it would be nice to DRY up the DSL for the simple cases. On the other hand, the setLocation calls don't really offend me that much, as I think the grammar is relatively stable, and the patterns are pretty clear, even if the code is a bit ugly on the surface.

Hassen Ben Tanfous hbt referenced this issue from a commit in hbt/coffee-script December 24, 2011
Hassen Ben Tanfous -#558 added --debug option to display line number e9339f0
Hassen Ben Tanfous hbt referenced this issue from a commit in hbt/coffee-script December 24, 2011
Hassen Ben Tanfous -#558 line number appears before instruction c5c5057
Hassen Ben Tanfous

I know people are working on their own solutions and something like sourceMap + advanced debugging in the browser would be awesome.

However, the least one needs is the line number in the compiled JS code.

I wrote a quick hack for it. available on my master branch
https://github.com/hbt/coffee-script

Run it using
coffee -cd file.coffee
-d or --debug will display the line number in a comment above the instruction in the compiled JS code

It's not much but it helps with the debugging.
Hopefully it will not take another year before this issue is fixed

Thanks

Hassen Ben Tanfous hbt referenced this issue from a commit in hbt/coffee-script December 25, 2011
Hassen Ben Tanfous -#558 automatically formatting the compiled JS code to match the line…
… numbers in the coffee script file
6a99b26
Hassen Ben Tanfous hbt referenced this issue from a commit in hbt/coffee-script December 25, 2011
Hassen Ben Tanfous -#558 beginning of work to support 1-1 line matching 0069c6d
Rob Tsuk

Recording source line numbers is now done over on https://github.com/rtsuk/coffee-script, if run coffee with --nodes you can see where it thinks the nodes are in the source. If anyone sees any errors in the locations reported, please let me know.

I'm moving on to trying to track the lines in the generated source and I'm failing to see any equivalently easy way to go about it.

Right now the the base class for all the nodes has a compile method that returns the generated source as a string. Each node's compile method has no way to know where in the generated source its contribution is going to land, and it also has no way to return the source line numbers to the caller who might.

One approach might be to stop using strings for returning code but create some CodeChunk object that can retain the source mapping. These code chunks could be then assembled into the resulting JavaScript and a map built at the same time.

Can anyone think of another approach? Any comments on this one? I'm afraid it's going to be a big change no matter how we slice it, so I'd love some feedback from the core contributors.

Nick Fitzgerald

@rtsuk regarding "CodeChunks", I created basically that exact thing and it is in the mozilla/source-map library because anyone who wants to use source maps in their compiler is going to run in to these problems.

https://github.com/mozilla/source-map/blob/master/lib/source-map/source-node.js

There is also some documentation here (find the "Source Node" section): https://github.com/mozilla/source-map/blob/master/README.md

Hope this helps! If you find it lacking, pull requests are welcome :)

Nick Fitzgerald

Oh, and I guess I forgot to mention it here, but the mozilla/source-map lib is BSD licensed now. I know there was concern about the license before, but it should be a non-issue now.

Hassen Ben Tanfous
hbt commented January 06, 2012

@lucaswoj @pmuellr
Actually implemented that idea.
Matching the compiled coffeescript (JS) to the original coffeescript file line by line.

How you can test it:

clone my repo

git clone git://github.com/hbt/coffee-script.git

checkout the branch

git checkout --track -b lines origin/line-numbers1-1

run cake build twice

./bin/cake build; ./bin/cake build

compile one of your coffeescript files
./coffee-script/bin/coffee -c test.coffee

produces the regular test.js

compile in debug mode
./coffee-script/bin/coffee -cd test.coffee
produces a version matching line numbers

Examples with the underscore library:
Original coffeescript file
https://gist.github.com/1572009

Compiled version
https://gist.github.com/1572005

Debug Version
https://gist.github.com/1571999
(notice the line numbers are a very close match)

Note: for whatever reason, the gist https://gist.github.com/1572009 starts at line 6 instead of line 1. Download the files and compare them in your editor as proof

lucaswoj
showell

@hbt I don't think that the line-by-line equivalence is the best solution going forward, but it's great to see a working prototype.

showell

Even though parser-aware line number support is around the corner, I still wonder how easy it would be to automatically match up CS line numbers to JS line numbers with a simple heuristic algorithm. For example, you could scan CS code, and each time you encounter a token for the first time, then look for the first occurrence of that token in the remaining JS code. This wouldn't give you an exact line-to-line match, but it would get you down to method-level granularity pretty reliably, I think.

You could avoid false matches by blacklisting keywords and/or really small words. Also, you'd always scan forward in the JS code, which I think is reliable. You'd have to ignore "var" statements in JS, so you don't get tripped up by hoisting.

Has anybody tried this kind of approach? Here's an example, done manually:

# key off "hanoi"
CS:
  hanoi = (ndisks, start_peg=1, end_peg=3) ->
    if ndisks
JS:
  var hanoi;

  hanoi = function(ndisks, start_peg, end_peg) {
    var staging_peg;
    if (start_peg == null) start_peg = 1;
    if (end_peg == null) end_peg = 3;
    if (ndisks) {
# key off "staging_peg"
CS:
      staging_peg = 1 + 2 + 3 - start_peg - end_peg
      hanoi(ndisks-1, start_peg, staging_peg)
JS:
      staging_peg = 1 + 2 + 3 - start_peg - end_peg;
      hanoi(ndisks - 1, start_peg, staging_peg);
# key off console
CS:
      console.log "Move disk #{ndisks} from peg #{start_peg} to #{end_peg}"
      hanoi(ndisks-1, staging_peg, end_peg)

  hanoi(4)
JS:
      console.log("Move disk " + ndisks + " from peg " + start_peg + " to " + end_peg);
      return hanoi(ndisks - 1, staging_peg, end_peg);
    }
  };

  hanoi(4);

Especially for server-based code, once you had a tool that could produce something like the above, it would be a relatively straightforward matter to build tools that let you find CS code sections based on JS line numbers.

showell

@jashkenas and others,

Check out this demo of CS/JS line number debugging that works with zero compiler support:

http://shpaml.webfactional.com/misc/underscore.htm

I've tested it on a few files, including underscore.coffee as shown in the link. It needs a little polishing in terms of packaging, but I think the basic approach could solve a lot of the problems folks have with debugging.

Gerald Lewis

Wow @showell -- really impressive!

Oscar Campbell
Hassen Ben Tanfous
hbt commented January 08, 2012

@showell

I definitely like your approach. I've started using coffeescript about a couple of weeks ago and the debugging was a major turn off. It's the whole 80/20 rule. 80% debugging compiled JS, 20% writing code with elegant syntax

Anyway, with the post-compilation formatting, I no longer have to read the JS code when debugging and I don't need any extra tools + the console statements match, I have breakpoints in the editor and the stacktrace reports the right line number.

In my opinion, the only thing missing in your solution is an auto-formatter and as soon as I start running into problems with my hack, I will fork yours and improve it.

Thanks again for working on this!

showell

@geraldalewis , @ozra, and @hbt: Thanks for the feedback.

@hbt I've been nibbling away at the tool this morning, and one thing that may be of interest to you is that I've started to separate concerns a bit. So, for example, there's now a module called side_by_side.coffee, which takes the equivalent of a source map and displays the CS and JS side by side. With that broken out, it should be easier for folks to enhance their own tooling.

@geraldalewis and @ozra, On the algorithm front I've actually simplified the algorithm a bit, by basically looking only at assignment statements in CS/JS. This seems to cut down on false matches significantly, while still being fairly precise. I'm mostly using underscore.js as my litmus test, and the particular style of coding in underscore.js seems to work well. I haven't tried it out on more "class"-centric code.

Obviously, the end game is here is full-on compiler support for mappings, and that's why I'm trying to keep the tooling separate from the temporary workaround of heuristic mapping.

There's probably a happy medium, where the CS transcompiler could give just a few hints to make my heuristic algorithm even more effective. Then, you wouldn't need full-blown line number support. An example would be blank lines. If CS did nothing else but create a source map between CS-blank-lines and JS-blank-lines, I think a little bit of tooling could effectively solve debugging problems for most reasonable flexible coders.

Rob Tsuk

@showell I'm glad you've made such progress on this, since I've not been about to make much headway on the generation side and new priorities at work mean I have to stop working on it for a while.

I hope someone decides to merge in #2000 as it will at least give one the source line numbers for nodes. Even if the output source maps don't arrive for a while it could be used in #2021 to provide source file and line numbers for the new errors that will be generated.

showell

I've done a little more work on the non-compiler solution to line mapping.

On the heuristics side, I've gotten line mapping down to the granularity of 25-line chunks, max. For easy code, it's much more fine-grained, but I err on the side of avoiding false matches. There's definitely room for improvement on line-matching, but the basic concept's proven out. I would love for folks to test this out and maybe file some issues on particularly difficult code to match.

On the UI side, there's now a web interface, where you can examine a whole directory's worth of .coffee and .js files. The front page lists all the coffee files, and if you click on the link, it makes a best attempt to find the matching .js file, then it shows the two files side by side.

The project is here:

https://github.com/showell/CoffeeScriptLineMatcher

To launch the web server, you do something like this:

 > coffee dashboard.coffee . 3000
Server running at http://localhost:3000/

The first cmd-line arg is the directory ("." in my example), and the second one is the port. So, in the browser, you'd launch:

http://localhost:3000/

The tool should work pretty much out of the box; you just need node.js and coffee.

Tane Piper

+1 @showell - Awesome work on this, it's been sticking around for a while and I'm glad we're finally seeing some good solutions to it that don't require browser vendors to get involved

showell

@tanepiper Thanks.

I've put some more polish into the CS/JS browser. I would love for folks to try it out:

https://github.com/showell/CoffeeScriptLineMatcher#readme

Bug reports are welcome, via github issues. In particular, I would like to hear about .coffee files that thwart my line-mapping algorithm. The current threshold is about 20 lines. I particularly want to avoid false positives, so if you can find a .coffee file that creates a false mapping, I'd really love to hear about it.

showell

An interesting variation on my hack would be to run each CS line though the compiler and look for the corresponding JS in the JS file. If you don't find a match, eat another line of CS and repeat, up to a certain amount of lines. If you don't find a match, just progress to the next line. If your matching criteria was somewhat fuzzy, at least ignoring trivial whitespace, I think you could come up with a pretty refined source map.

Jann Horn

@rtsuk That patch looks awesome! With a little ugly hack, this should work really good - just add a function to Base that calls @compile and wraps the result in a comment with the source area, then use that function everywhere instead of compile(). Downside: uglier generated code. Thoughts?

Maybe I'll try that tomorrow.

Rob Tsuk

@thejh Check out my comment from the 5th on the challenges left. It doesn't seem quite so straightforward to me, but fresh eyes might do better.

Definitely check out @fitzgen's SourceMap implementation. I think it's part of any solution.

Jann Horn

@rtsuk Actually, @shesek had a good idea on how to do it in chat, I think. As I said, I'll try tomorrow.

Jann Horn

Aaaaalright... see mappings work here:

Coffee: https://raw.github.com/thejh/coffee-script/line-mapping/src/lexer.coffee
JS: http://thejh.github.com/lexer.coffee.html - click chars to see the corresponding coffee lines

Server for generating the mappings from coffee files: https://github.com/thejh/coffee-script/blob/line-mapping/examples/code_mapping.coffee

Jann Horn

@jashkenas I hope my patch isn't too ugly for pulling it?

Michael Ficarra
Collaborator

Here's a diff from master containing contributions from both @rtsuk and @thejh, and here's a diff from @rtsuk's pull #2000, containing just @thejh's contributions.

Michael Ficarra
Collaborator

@thejh: after a very brief look over the code, can't you pretty it up a little bit? Instead of replacing

"#{fun}.apply(#{ref}, #{splatArgs})"

with

CodeString this, fun, '.apply(', ref, ', ', splatArgs, ')'

, can't we just do @s "#{fun}.apply(#{ref}, #{splatArgs})", adding s: -> CodeString.apply this, arguments to Base?

Jann Horn

Speed might be an issue - I didn't optimize anything yet, but still, it's not so good...

on master: 1.63s for cake test
on line-mapping: 4.06s for cake test

Michael Ficarra
Collaborator

@thejh: can you also bench @rtsuk's branch as well so we can see how much your contribution affects that number? I would also like to see how this performs when CodeString is defined as -> [].reduce.call arguments, ((memo, x) -> memo + x), "" unless a line mapping flag is present.

Jann Horn

@michaelficarra Hmm, right, those things should make it look better and be faster.

I'm getting 1.52s on his branch - well, I didn't average multiple runs or anything, but seems to be roughly equal to master.

Jann Horn

@michaelficarra Prettified it.

Jann Horn

I have working mappings now, all nodes use @s everywhere, and the mappings even have column precision (not just line precision). Have a look at http://thejh.github.com/lexer.coffee.html and https://raw.github.com/thejh/coffee-script/line-mapping/src/lexer.coffee again - each green character means "source data for this position is different from source data for last position". Click stuff for node type, source line and source column. :)

Jann Horn

Oh, btw, to try it out yourself, you'll have to run cake build:full. After that, run examples/code_mapping.coffee.

Jann Horn

Only issue I could find until now is string interpolation.

Jann Horn

I added a little stack trace hack (based on what coco does, too) that hacks into stack traces from the root module that get thrown immediately. Example:

[jann@Jann-PC examples line-mapping]$ ../bin/coffee foobar.coffee
TypeError: Cannot read property 'b' of undefined
    at Object.<anonymous> (/home/jann/gitty/coffee-script/examples/foobar.coffee:10:46)
    at Object.<anonymous> (/home/jann/gitty/coffee-script/examples/foobar.coffee:1:7)
    at Module._compile (module.js:432:26)
    at Object.run (/home/jann/gitty/coffee-script/lib/coffee-script/coffee-script.js:73:27)
    at /home/jann/gitty/coffee-script/lib/coffee-script/command.js:138:29
    at /home/jann/gitty/coffee-script/lib/coffee-script/command.js:112:18
    at [object Object].<anonymous> (fs.js:115:5)
    at [object Object].emit (events.js:64:17)
    at afterRead (fs.js:1111:12)
    at Object.wrapper [as oncomplete] (fs.js:254:17)

10:46 is the correct token in the coffee file, 1:7 is incorrect - well, that line comes from the safety wrapper.

showell

@thejh This is awesome.

Would it be possible to create some automated regression tests for your patch?

In my non-compiler-based hack to get (row-only) mappings, I have the following file:

https://github.com/showell/CoffeeScriptLineMatcher/blob/master/test/test.coffee

Basically, it reads a JSON file that has the mappings from the last time I run the tests, and then it ensures that the new mappings are a superset of the old mappings. I would think that something like this would be useful for getting your patch accepted. If there are any cosmetic issues remaining on the patch, I'd love to see it get pulled for the functionality alone, and then, as long as there are good tests, future patches could tighten up style issues. (I think the patch looks great BTW, but I haven't looked at it in great depth.)

Also, do you write the source maps out to a file anywhere, or is it all in memory? In either case could you post a gist of what the source mappings look like?

Finally, this is a minor issue, but something about your patch causes Github to choke on color syntax (unless I'm just misreading the code). This is obviously not your fault, but is there a workaround?

https://github.com/thejh/coffee-script/blob/line-mapping/src/nodes.coffee

Jann Horn

Basically, it reads a JSON file that has the mappings from the last time I run the tests, and then it ensures that the new mappings are a superset of the old mappings.

Hmm... should be doable.

Also, do you write the source maps out to a file anywhere, or is it all in memory?

All in memory.

In either case could you post a gist of what the source mappings look like?

Sure. Code:

S=[];
Object.keys(js.sources).forEach(function(jschar){
  S.push(
  { jsindex:+jschar
  , location:js.sources[jschar].location+''
  , nodetype:js.sources[jschar].constructor.name
  })
})
S.map(function(s){return s.jsindex+': '+s.nodetype+' at '+s.location}).join('\n')

Result: https://gist.github.com/1616246

something about your patch causes Github to choke on color syntax (unless I'm just misreading the code). This is obviously not your fault, but is there a workaround?

Wrong color is probably caused by #### - I guess github reads it as start of a comment block.

Rob Tsuk

@thejh Nicely done!

My notion for testing this was to grep for unique string literals in both source and generated files and making sure the map is right for them.

showell

@thejh Disregard my comment about color syntax, at least in the context of this patch. The master branch is affected by the same issue. Before I try to file an issue for Github, has anybody else raised this issue before?

@rtsuk @thejh I think grepping for string literals is a good sanity check on line mappings, but I also feel like it would be pretty easy to bootstrap an automated approach that checks every mapping. You would want some stable files to test against, and I think the files in https://github.com/jashkenas/coffee-script/tree/master/test would be relatively stable. If folks modified those files, they would need to scrutinize the new mappings, but I don't think that would be too onerous.

showell

@thejh I think there would be some value in having the compiler write source maps to the file system, so that external tools could easily find them. I know that external tools could directly re-invoke the source mapping code by calling into the compiler as a library, but this could be brittle for people that are running multiple coffeescript versions, and, of course, it would be inefficient for the tools to have to recompile the code.

Jann Horn

@showell For writing them to the fs, it'd be cool to be able to just use the source map format that, as @atrefz said, is already usable in chrome. So, we need to be able to write it.
When that works, we need a reader module for node.js that hooks into Errors and rewrites their stacktraces. Thoughts?

Jann Horn

Created an issue for hooking into stacktraces in node: joyent/node#2537

showell

@thejh

I can only speak to my own use cases, but for me, Chrome support is a fairly minor issue, but if the format for Chrome source maps is easy enough to manipulate, then I'm all for it.

On the stacktraces, it would be useful if they were still in Javascript (or maybe both languages), because when I debug, it's generally at the Javascript layer. The source line mapping is useful to know where to apply the fix without fishing through the CS code, but I don't want it to be a completely black box.

Obviously, most of the people on this thread are probably fairly advanced CS users, so we might not fit the typical profile of user that will be truly helped by this effort. If you write a lot of CS code, it often just works the first time you write it, and, also, more experienced developers develop a good intuition for working more incrementally on tougher coding tasks, so you tend to know where the errors are going to happen, even if you're not confident in your first writing of the code.

I don't use CS with Rails at the moment, but there are probably lots of Rails users who work in Ruby 90% of the time, and then only dabble in CoffeeScript, and it might not even be their choice to use it. For those folks, there might be some kind of tooling that makes sense to the Rails mindset, and it might not necessarily be browser support. For example, it might be more about integrating line number support into asset packaging.

Since it's impossible to predict every use case, then I think the best strategy for now is to make the tools as open and "standard" as possible, which seems to be the direction you're going.

Jann Horn

Oh, btw: Chrome uses the WebKit Web Inspector, right? And @atrefz said that it has experimental support for source maps? Well then... node-inspector also uses that inspector. WIN! :)

showell

@thejh @michaelficarra Just trying to think outside the box a bit--I wonder if anybody has tackled the traceback issue in an internationalization context. There are two orthogonal problems for plugging in line numbers to tracebacks:

  1. getting a hold of the traceback info at the right time (preferably when there's still a data structure or object to manipulate)
  2. reformatting the traceback (a simple matter of coding).

It's obviously the first problem where I think folks working on I18N might have some insight.

Jann Horn

About the tests: I'm pretty sure it's not really possible for nodes to randomly get wrong positions as there's no manual position tracking, but it's possible for the positions to get dropped... Hmm, ok, this means that test files might be a good idea. Does anyone else want to do that or should I? :D
So basically, make JSON from the mappings and check whether the JSON on the disk is the same?

showell

@thejh I'd volunteer to write the tests, but I think it would complicate matters too much to have yet another fork of a fork. That's my excuse, and I'm sticking to it. :)

I'm happy to review any tests that you write. I think the following code should be pretty easy to adapt to your fork:

https://github.com/showell/CoffeeScriptLineMatcher/blob/master/test/test.coffee

I would maybe cherrypick five or six files from this directory as source files for the regression tests:

https://github.com/jashkenas/coffee-script/tree/master/test

Jann Horn

@showell That excuse becomes invalid as soon as my patch was merged. :P

Well, if nobody has done this stuff tomorrow, I might do it.

showell

FYI, I've made some nice progress on the CoffeeScriptLineMatcher tool, which can help with your workflow in debugging coffeescript by showing CS/JS side by side with line mappings. As I mentioned earlier in the thread, the tools doesn't require any help from the compiler itself, which makes it easy to use on old coffeescript versions, especially if you don't need total precision.

Here's a screencast:

http://www.youtube.com/watch?v=dEze_TaORJs&feature=youtu.be

Here's the github project:

https://github.com/showell/CoffeeScriptLineMatcher

If the changes from @rtsuk and @thejh get merged, I intend to upgrade the tool to take advantage of any line-mapping support from the compiler itself.

igorbernstein

whats blocking this from being merged?

Michael Ficarra
Collaborator

@igorbernstein: The recent implementation by @thejh/@rtsuk complicates the compiler a lot. It still needs a lot of serious discussion.

showell

@michaelficarra How do we start a serious discussion about merging these changes? I thought "what's blocking this from being merged?" was a good start--thanks, @igorbernstein .

Of course, the patch complicates the compiler to some degree. You don't get line number support for free. Yet somehow every grown-up programming language has line support.

The way to implement line number support in a programming language is that you capture line numbers (and possibly column offsets) during the lexer/parse stage, then you pass them on to the builder stage, then you emit them as part of the metadata. Ugly? Maybe. Complicated? Not really.

I fully endorse the @thejh/@rtsuk patch. I'd like to see tests, but if that's the only hindrance, let's make it explicit.

What are the discussion points for this patch? Specifically, what are the roadblocks? Code review? Priority? Tests? Justification of the necessity?

igorbernstein

@michaelficarra has there been any movement on this (one way or another)? I will be starting a new project soon, and need to pitch a technology stack to my client. This issue plays a big role in our decision.

Jacob Beard

I don't want to turn this into a "me too" thread, but I just wanted to second the comment by @igorbernstein . I've been pitching coffeescript at my place of business, and debugger support/line number mapping has been a sticking point. It would be great if this could be pushed forward.

showell

@michaelficarra I don't mean to be too impatient, but I asked these questions 18 days ago: "What are the discussion points for this patch? Specifically, what are the roadblocks? Code review? Priority? Tests? Justification of the necessity?" Any thoughts?

@igorbernstein/@jbeard4 Have you considered pitching to your clients/peers that they just work off of the fork for now?

@thejh Have you had any feedback from folks using your fork (including yourself, of course)?

Patrick Mueller

You know, another thing that we'll need, as I'm starting to use CoffeeScript on the command-line, is reverse line-number mapping for stack traces from node (or wherever). Instead of seeing JS line numbers in stack traces, I should be seeing CoffeeScript line numbers.

This is a 'node' thing - we'll have to teach node how to deal with stack maps (or whatever), if it doesn't already understand them.

Anyone poked on that from the node side yet, via ml discussion or issue?

Nothing we can do about it (I don't think) from the CoffeeScript side, but it is relevant to the whole "make it easier to debug CoffeeScript" issue.

showell

@pmuellr See this issue on node:

joyent/node#2537

Long story short, there probably won't be much direct support in node itself, but I think it would pretty easy to create reverse-line-number tooling even without direct node support.

Patrick Mueller

@showell thanks for the link

It's the wrong answer, to use prepareStackTrace. I already hack prepareStackTrace myself, for other reasons. :-) :-(

Ideally node could some how recognize that stack maps were available, and - at the "native level" - do the line number conversion. Once we have stack maps (or whatever) we can look to see what we can do at the node (or prolly even v8) level.

Jann Horn

@showell No, I didn't use coffeescript much in the meantime, and I never had to work with stacktraces.

@pmuellr Well, my patch already hacks stacktraces (although it uses prepareStackTrace) - see #2050 (comment) for an example.

Gerald Lewis

I think feel everyone's pain in not having debugging support, but I think @michaelficarra's prudence is justified.

There's a low signal/noise ratio in this thread; forgive me if these questions have already been addressed:

  • How does this handle errors within the CoffeeScript source itself?
  • How does this handle errors when CoffeeScript source is intermixed with JS? (e.g., running a CoffeeScript script in Node that requires a JS module that has a syntax and/or runtime error)
  • Comments?
  • How accurate is it?
  • Could tests be added to show the desired output/ensure this feature works correctly?
  • I hacked up a solution a few months back. @thejh's patch appears better put together than mine, but seems to have similar functionality only with more overhead.

I'm being critical, so I'd like to add that @thejh's patch looks promising and is certainly ambitious!

Jeremy Ashkenas
Owner

@geraldalewis++ I share all of those concerns / sentiments.

Michael Ficarra
Collaborator

@jashkenas: we should get together on IRC sometime soon to go over a strategy for determining what solution is most appropriate for CS. I'll try to be on whenever I'm available. I like the approach taken by @thejh, but there's certainly concerns about speed, completeness, correctness, output format, testing, etc.

Others: Sorry for not giving this the priority it deserves. I know it's very important to some of you. Though the comments above by @geraldalewis and @showell show that this isn't quite finished.

Eric Hartford

+1 node.js user, following this issue closely.

showell

FYI, I have created a demo page that shows how line number mappings get displayed with my CoffeeScriptLineMatcher tool:

http://shpaml.webfactional.com/misc/cslm_demo.htm

The tool would be much improved with more precise line number mappings from the compiler, but it does a decent job of figuring out mappings now.

Aaron Jensen

source maps in chrome: http://www.youtube.com/watch?v=-xJl22Kvgjg is there already support for this?

showell

@aaronjensen CS does not yet generate source maps. Some of the patches that have been discussed on this thread get CS closer to supporting source maps, as well as providing line number support in general. The patches are on hold due to concerns about speed, completeness, correctness, output format, testing, etc.

Rob Tsuk
rtsuk commented March 21, 2012

@showell How did you find out that my pull request is on hold due to concerns about speed, completeness, correctness, output format, testing, etc? The only comment from an authority that I can see is @jashkenas congratulating me for the pull request number.

Jeremy Ashkenas
Owner

Looks like source map support is heating up. Do we know when Chrome proper is likely to incude them, and not just Chromium?

Michael Ficarra
Collaborator

@rtsuk: Check a few posts above.

Rob Tsuk
rtsuk commented March 21, 2012

@michaelficarra I don't see any comments about my pull request at all. I do seem comments about the one by @thejh .

Why not use the comments space on the pull request to comment on pull requests, rather than this megathread?

Brandon Satrom

@jashkenas Chrome Canary (Nightly Build) has Source Maps support today in dev tools, putting it about 6 weeks away from stable.

Paul Irish

@jashkenas (I just confirmed with our engineer).. Source maps is in m18, which is in beta and expected to ship to stable.. soon. (It's been 6 weeks since m17 shipped.)

Also last night we published a big guide on source maps: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/ @rtsuk knew most of this already, but it should help illuminate what's going on here. :)

Jeremy Ashkenas
Owner

That's fantastic. I'd love to try and get one of the branches merged, and a release cut, for when it lands in Chrome proper.

jimtla

Source maps are in chrome proper - version 18 has support.

There's a nice explanation here which, incidentally, calls us out.

Eric Hartford

Is there a coffee fork that enables source maps compatible with chrome 18's new feature?

Davide Callegari

I'm looking forward to test this in chrome 18 :)

Gian Marco Gherardi
gimmi commented May 01, 2012

+1

I'm waiting for this feature to start taking seriously coffeescript

David Rees

Note IDEs that provide their own debugging environment can do the source mapping as well, they just need the sourcemap from coffeescript. For example JetBrains IDEA has a feature request for this (http://youtrack.jetbrains.com/issue/IDEA-84442) and Firefox still has this issue that folks can vote for (https://bugzilla.mozilla.org/show_bug.cgi?id=618650), but neither is going to move until they have something generating sourcemaps for them to play with.

Emile Cantin

Chrome 19 is now out, is there any progress on this? I'm really looking forward to debug directly in CoffeeScript.

Jeremy Ashkenas
Owner

'Fraid there's nothing to report yet progress-wise, but it's next on the list.

Chuck Lauer Vose

You're all amazing and we love you. I've been using Coffeescript on a production project for the last two months and I'm absolutely in love with it. This would just be a little extra frosting on the cake.

Simon Wade

Awesome guys, can't wait for this to land.

Gordon Mohr

I realize I'm way late to an old and overlong thread, but wanted to throw another offbeat hybrid idea out there:

Indicate the two different "line" numbers by using two different line-end conventions in the same compiled file. For example, the compiled/JS line numbers would be indicated by traditional line-ends (CR/LF/CRLF), and the original-source line-numbers by some other harmless whitespace, such as FF (0x0C) or VB (0x0B).

That is, every JS line has a traditional line-length and line-end (no overlong lines), but only those representing another line forward in the CS source also include the new-convention secondary line-end. (And, this approach also allows for multiple source-line-ends to a single output line-end.)

Code editors and line-reporting code could offer a toggle for how they number lines.. or simply report both when dual conventions are noticed in the file. For example...

underscore_coffee.js:64;83

...where the ';83' indicates the secondary-convention line-number.

igorbernstein igorbernstein referenced this issue in sstephenson/sprockets October 08, 2012
Closed

Source Map support #310

Matt Tagg

Given that Redux now supports this. What is the implication for this repo?

Politics aside, and speaking strictly pragmatically for the benefit of new users such as myself, should we be switching to redux as the future compiler of choice?

Michael Ficarra
Collaborator

@wamatt: I would recommend sticking with this more stable compiler for serious projects for now as the kinks are worked out of my compiler over the next few months. That said, if you can go over the compiled output manually (or if your program has good test coverage and your tests still pass), and it looks good to you -- which it really should for most programs -- go ahead and take advantage of the source map support.

Matt Tagg

@michaelficarra Thanks, that sounds sensible. Keep up the great work! :)

Nick Karnik theoutlander referenced this issue in nikhilk/scriptsharp December 19, 2012
Open

C# Source Level Debugging #306

Devon Govett

What's the status on this? @michaelficarra's Redux compiler seems to support them and there is at least one pull request for support in this compiler but relatively little discussion from the maintainers. Is sourcemap support still something being planned? Is something holding it back? Just looking for updates.

Jeremy Ashkenas
Owner

@devongovett -- I think the status is basically what you said ... they work in Redux, and there are a couple of probably working branches with pull requests over here as well. One in particular I've been keeping my eye on and corresponding via email about, that looks very promising.

That said, I'd like to wrap up one new release of CoffeeScript with official "literate" support before starting to look at 'em in earnest. If you want to help move things along, feel free.

Nami-Doc
Collaborator

PONG, 3 years after

Michael Ficarra michaelficarra closed this March 04, 2013
Michael Ficarra
Collaborator

Oh, wow, we can finally close this. The oldest open CoffeeScript issue. Well, here goes :smile:.

edit: Actually, I forgot about the recently re-opened issue #77. That issue's even older than me.

Andrew Schaaf

Congratulations!

Adam Stankiewicz

Unfortunately :cake: was a lie ;-) Thank you!

Matt Tagg

Woot!

Terry Jones

Awesome ticket :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.