With all the nascent alt-JS things people are playing with, talked about on this InfoQ blog post, I got to thinking a while back how we could make debugging a little better for these folks in WebKit's Web Inspector.
With my familiarity of Java's innards, I happened to think about supporting a mode of using an alternative source file, and line number mappings between the original source and the generated source, to allow folks to have some level of source-level debugging in their original language. That would be for systems which actually generate JavaScript from the original language.
Java supports meta-data in it's .class files for this sort of information, and I've seen it used for things like debugging Groovy in Eclipse using the stock Java debugger. Not a perfect story, but useful.
So I opened up Bug 30933 - Web Inspector: support for debugging alt-JS files which generate JS. Feel free to drop ideas there.
Anyhoo ...
While chatting with someone who could make use of this, they noted that
their biggest problem was that eval()
doesn't do a very good
job of providing information about syntax errors in the eval()
'd
code. Really? Time for some experiments.
First, why care about eval()
in the first place? Since
it's evil. If code is
being generated from some alternate source, don't you end up with JavaScript
code you can just use in the browser with a <script>
element? Sure, you can do it that way. But
why do an off-line compile if you could do the compile in the browser?
It's also the case that some 'traditional' JavaScript libraries like
Dojo may end up (depending on
your configuration), downloading your source via XHR and then running it
via eval()
instead of using <script>
elements.
Getting good diagnostic information from eval()
would be good for lots of
people.
On to the experiment:
Here's the source of an HTML file to try out with different browsers. There's a link in
the HTML which, when clicked, will run the clickMe()
JavaScript
function. That function builds a string which will be passed into eval()
.
I added 100 or so newline's in the source before a string that all the
browsers would actually choke on (took me a minute; my first guesses at
things that would cause syntax errors didn't). The 100 empty lines are to see
what kind of line numbers JavaScript will tell us about, if at all; if line numbers
with syntax errors are reported, we want to see a line number like 100, not
13 (the line in the source that invokes eval()
).
The page is also available on my web site.
Below the source are the results you see in the browser after clicking;
these are the properties of the exception object generated by eval()
,
one per line.
HTML source for test:
1 <html> 2 <head> 3 </head> 4 <body> 5 <a href="javascript:clickMe();">click me!</a> 6 <p> 7 <div id="output" style="font-family: monospace"></div> 8 <script> 9 function clickMe() { 10 var lines99 = new Array(100).join("\n"); 11 evalString = lines99 + "for ]](x does not compute)]]\n"; 12 try { 13 eval(evalString); // this is line 13 of the source file 14 } 15 catch(e) { 16 dumpException(e); 17 } 18 } 19 20 function dumpException(obj) { 21 var result = "Exception:<br>\n"; 22 for (var key in obj) { 23 result += " " + key + ": " + obj[key] + "<br>\n"; 24 } 25 document.getElementById("output").innerHTML = result; 26 } 27 </script> 28 </body> 29 </html>
WebKit nightly r50423 on Mac (basically, Safari):
Exception: message: Parse error line: 100 sourceId: 4837249224 name: SyntaxError
Opera 10.00 Build 6652 on Mac:
Exception: message: Statement on line 6: Syntax error stacktrace: n/a; see opera:config#UserPrefs|Exceptions Have Stacktrace opera#sourceloc: 6 stacktrace: false
Google Chrome 4.0.223.11 on Mac:
Exception: message: Unexpected token ] stack: SyntaxError: Unexpected token ] at clickMe (http://muellerware.org/exception-in-eval.html:12:8) at unknown source type: unexpected_token arguments: ] name: SyntaxError
Firefox 3.5.4 on Mac:
Exception: message: missing ( after for fileName: http://muellerware.org/exception-in-eval.html lineNumber: 112 stack: eval("[100 \n's elided]for ]](x does not compute)]]\n")@:0 clickMe()@http://muellerware.org/exception-in-eval.html:13 @javascript:clickMe();:1 name: SyntaxError
IE 8.0.7100.0 on Windows 7 RC:
Exception: name: SyntaxError message: Expected '(' number: -2146827283 description: Expected '('
Google Chrome 3.0.195.27 on Windows 7 RC:
Exception: message: Unexpected token ] stack: SyntaxError: Unexpected token ] at clickMe (http://muellerware.org/exception-in-eval.html:13:8) at unknown source type: unexpected_token arguments: ] name: SyntaxError
Yikes, not a pretty picture! WebKit was the only one that got the line number I wanted. But it gave a pretty crappy "message". Nice seeing the "stack" entries for some of the implementations.
To be honest, things like the "message" - the reason why you got the syntax error - I expect to be somewhat implementation dependent. Although I expect something (looking at you, JavaScriptCore!).
There's a question of semantics, of course. The exception generated
from WebKit, with the line number of the eval()
'd source,
would be confusing had I not caught the exception (though perhaps I'd see
something different in the debugger had I not caught the exception).
In reality, what you may really want
to see, structurally, is something like Java's nestable
InvocationTargetException
,
for eval()
, because there are multiple levels of things going
on here; for the ultimate evil, eval()
may end up doing some of it's
own eval()
's.
In any case, it would be nice to see some of this stuff standardized. In ECMAScript 6, I guess.