Skip to content

Instantly share code, notes, and snippets.

@geraldalewis
Created May 15, 2011 23:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geraldalewis/973659 to your computer and use it in GitHub Desktop.
Save geraldalewis/973659 to your computer and use it in GitHub Desktop.
Debug mode for running .coffee scripts #558, #987

Debug mode for running .coffee scripts #558, #987

Adds a --debug option for .coffee scripts that outputs more helpful error messages (mapping compiled .js lines of code to the input .coffee file's lines).

This branch should be considered experimental at the moment -- it serves as a proof-of-concept and to expose additional issues with adding debugging support to CoffeeScript

Current output:

TypeError: string is not a function
    at String.CALL_NON_FUNCTION (native)
    at Object.<anonymous> (/Users/geraldlewis/Work/Interactive/projects/coffee-script/errs/err.coffee:10:3)
    at Module._compile (module.js:420:26)
    at Object.run (/Users/geraldlewis/Work/Interactive/projects/coffee-script/coffee-script/lib/coffee-script.js:68:12)
    at /Users/geraldlewis/Work/Interactive/projects/coffee-script/coffee-script/lib/command.js:120:29
    at /Users/geraldlewis/Work/Interactive/projects/coffee-script/coffee-script/lib/command.js:90:26
    at [object Object].<anonymous> (fs.js:107:5)
    at [object Object].emit (events.js:61:17)
    at afterRead (fs.js:970:12)
    at wrapper (fs.js:245:17)

--debug Output:

  TypeError: string is not a function

  in err.js on line 10
  --------------------
  > 10 |   s();

  in err.coffee on line 10
  ------------------------
   7 | 
   8 | 
   9 | for k,v in [1,2,3]
> 10 |   s()
  11 |   try
  12 |     #log undef
  • Uses a few strategies outlined in #558, namely @atrefz 's --debug compiler option with line number comments, @andrewschaaf 's "FUGLY" option (though modified so that the end user never sees the ugly JS line number comments)
  • Speaking of, @andrewschaaf has done some great work on this same issue, which I'm having trouble locating at the moment
  • Uses @aseemk 's suggestion for Stylus style error messages (#1351)
  • Also fixes #987 (stack trace refers to [filename].js instead of [filename].coffee)

Caveats

  • only works with node.js at the moment
  • only works for running and eval-ed .coffee scripts (see below)
  • needs a lot of testing; I've not tested it with a lot of sample bugs

Here's the branch: https://github.com/geraldalewis/coffee-script/tree/debug

Here's the commit: https://github.com/geraldalewis/coffee-script/commit/9d0fa7cc4d4b73e8de1a0a8179753ba3fa0df1b8

#What works#

###Running .coffee files###

bin/coffee -d ../errs/err.coffee 

  TypeError: string is not a function

  in err.js on line 11
  --------------------
  > 11 |     s();

  in err.coffee on line 10
  ------------------------
   7 | 
   8 | 
   9 | for k,v in [1,2,3]
> 10 |   s()
  11 |   try
  12 |     #log undef

###Eval### ...Sort of -- this works:

bin/coffee -bed 'i = 0; undef()'

but this fails for some reason (some bug in the DebugCSFile.error, I think -- seems to happen if < 2 lines of .js)

bin/coffee -bed 'undef()'

#What doesn't work# There are a few classes of errors I'm struggling to get debug info from. I have no solutions at the moment, but some ideas below.

##Errors in CoffeeScript## @jashkenas 's first question to me was what kind of output he'd see if there was an error in src/scope.coffee. I inserted a bug into Scope's constructor (a call to undef()), recompiled CoffeeScript, and ran coffee -bed 'i = 1'

dev:coffee-script(debugging)$ coffee -bed 'i = 1'
ReferenceError: undef is not defined
    at new Scope (/Users/geraldlewis/Work/interactive/projects/coffee-script/coffee-script/lib/scope.js:10:7)
    ...

Clearly, debug didn't work -- we have the same node.js error message output, instead of the expected:

ReferenceError: undef is not defined

in scope.coffee on line 21
--------------------------
  19 |constructor: (@parent, @expressions, @method) ->
> 21 |  undef()
  22 |  @variables = [{name: 'arguments', type: 'arguments'}]

My mistake was forgetting that coffee uses pre-compiled .js files to run CoffeeScript. debug relies on CoffeeScript compiling a .coffee file -- the .coffee file needs to be present so that the executing .js file's line numbers can be mapped to their CoffeeScript source. Since we no longer have a reference to the original scope.coffee file, we don't have any way of associating the lines of code where an error occured in scope.js.

Compounding the issue: because debug needs to re-compile the source .coffee file(s) (to insert the line-number comments mapping the line of .js to its respective line of .coffee) a bug in the compile pipeline is a bug in debug...

###Possible Solutions###

  1. cake build ensures a clean, working copy of CoffeeScript is available even if a bug is introduced into its source

  2. introduce a bug into the source of CoffeeScript

    # in source.coffee
    constructor: ()->
      undef()
    
  3. compile the buggy CoffeeScript via cake build

  4. run a bug-free script to see if an error occurs

    bin/coffee -be 'i = 1'
    
  5. on error, grab the buggy .js file from the error stack

    at new Scope (coffee-script/lib/scope.js:10:7)
    
  6. somehow get the .js file's associated .coffee file

    # in scope.js
    //@source_file:coffee-script/src/scope.coffee
    
  7. and send it to the clean working copy of CoffeeScript

  8. output that debug message...

##Docco## Debugging Docco represents a subtly different class of issues than debugging CoffeeScript. Like CoffeeScript, docco.coffee has already been compiled to docco.js when bin/docco requires it:

#!/usr/bin/env node

var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

process.ARGV = process.argv = process.argv.slice(2, process.argv.length);
require(lib + '/docco.js'); #completely bypasses the .coffee compilation stage

We have the same issue -- since we no longer have a reference to the original .coffee script, we don't have any way of associating the line of JavaScript code with its originating CoffeeScript line.

###Possible solutions:###

  1. run docco via bin/coffee
  • modify command.coffee run to allow args to be sent via "<" to the running script if the -d option is set:

    coffee -d src/docco.coffee < src/some_project.coffee
    # for the `run`ning src/docco.coffee script, process.ARGV would = process.ARGV[2..]
    
  1. a --debugsource flag (oof?)
  • not sure how this would work exactly, but some loose ideas:

  • debugsource points to the .coffee source file or src/ folder for the running script

  • if an error is encountered in the node.js runtime

  • use process.on 'uncaughtException' to catch it and save details as "stack"

  • run coffee-script.debug ( debugsource, stack ... )

  • (this recompiles the debugsource so that the CoffeeScript lines can be associated with their JS counterparts )

    docco --debugsource=src/docco.coffee src/some_project.coffee

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment