Files
coffeescript/docs/v2/annotated-source/coffeescript.html
2023-09-19 08:59:28 -07:00

845 lines
39 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<title>coffeescript.coffee</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To &hellip;</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page_wrapper">
<div id="jump_page">
<a class="source" href="browser.html">
browser.coffee
</a>
<a class="source" href="cake.html">
cake.coffee
</a>
<a class="source" href="coffeescript.html">
coffeescript.coffee
</a>
<a class="source" href="command.html">
command.coffee
</a>
<a class="source" href="grammar.html">
grammar.coffee
</a>
<a class="source" href="helpers.html">
helpers.coffee
</a>
<a class="source" href="index.html">
index.coffee
</a>
<a class="source" href="lexer.html">
lexer.coffee
</a>
<a class="source" href="nodes.html">
nodes.coffee
</a>
<a class="source" href="optparse.html">
optparse.coffee
</a>
<a class="source" href="register.html">
register.coffee
</a>
<a class="source" href="repl.html">
repl.coffee
</a>
<a class="source" href="rewriter.html">
rewriter.coffee
</a>
<a class="source" href="scope.html">
scope.litcoffee
</a>
<a class="source" href="sourcemap.html">
sourcemap.litcoffee
</a>
</div>
</div>
</li>
</ul>
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>coffeescript.coffee</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-1">&#x00a7;</a>
</div>
<p>CoffeeScript can be used both on the server, as a command-line compiler based
on Node.js/V8, or to run CoffeeScript directly in the browser. This module
contains the main entry functions for tokenizing, parsing, and compiling
source CoffeeScript into JavaScript.</p>
</div>
<div class="content"><div class='highlight'><pre>
{Lexer} = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./lexer&#x27;</span>
{parser} = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./parser&#x27;</span>
helpers = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./helpers&#x27;</span>
SourceMap = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./sourcemap&#x27;</span></pre></div></div>
</li>
<li id="section-2">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-2">&#x00a7;</a>
</div>
<p>Require <code>package.json</code>, which is two levels above this file, as this file is
evaluated from <code>lib/coffeescript</code>.</p>
</div>
<div class="content"><div class='highlight'><pre>packageJson = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;../../package.json&#x27;</span></pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-3">&#x00a7;</a>
</div>
<p>The current CoffeeScript version number.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.VERSION = packageJson.version
<span class="hljs-built_in">exports</span>.FILE_EXTENSIONS = FILE_EXTENSIONS = [<span class="hljs-string">&#x27;.coffee&#x27;</span>, <span class="hljs-string">&#x27;.litcoffee&#x27;</span>, <span class="hljs-string">&#x27;.coffee.md&#x27;</span>]</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-4">&#x00a7;</a>
</div>
<p>Expose helpers for testing.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.helpers = helpers
{getSourceMap, registerCompiled} = SourceMap</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-5">&#x00a7;</a>
</div>
<p>This is exported to enable an external module to implement caching of
sourcemaps. This is used only when <code>patchStackTrace</code> has been called to adjust
stack traces for files with cached source maps.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.registerCompiled = registerCompiled</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-6">&#x00a7;</a>
</div>
<p>Function that allows for btoa in both nodejs and the browser.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">base64encode</span> = <span class="hljs-params">(src)</span> -&gt;</span> <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> <span class="hljs-keyword">typeof</span> Buffer <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;function&#x27;</span>
Buffer.<span class="hljs-keyword">from</span>(src).toString(<span class="hljs-string">&#x27;base64&#x27;</span>)
<span class="hljs-keyword">when</span> <span class="hljs-keyword">typeof</span> btoa <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;function&#x27;</span></pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-7">&#x00a7;</a>
</div>
<p>The contents of a <code>&lt;script&gt;</code> block are encoded via UTF-16, so if any extended
characters are used in the block, btoa will fail as it maxes out at UTF-8.
See <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem">https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem</a>
for the gory details, and for the solution implemented here.</p>
</div>
<div class="content"><div class='highlight'><pre> btoa <span class="hljs-built_in">encodeURIComponent</span>(src).replace <span class="hljs-regexp">/%([0-9A-F]{2})/g</span>, <span class="hljs-function"><span class="hljs-params">(match, p1)</span> -&gt;</span>
<span class="hljs-built_in">String</span>.fromCharCode <span class="hljs-string">&#x27;0x&#x27;</span> + p1
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">&#x27;Unable to base64 encode inline sourcemap.&#x27;</span>)</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-8">&#x00a7;</a>
</div>
<p>Function wrapper to add source file information to SyntaxErrors thrown by the
lexer/parser/compiler.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">withPrettyErrors</span> = <span class="hljs-params">(fn)</span> -&gt;</span>
(code, options = {}) -&gt;
<span class="hljs-keyword">try</span>
fn.call @, code, options
<span class="hljs-keyword">catch</span> err
<span class="hljs-keyword">throw</span> err <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;string&#x27;</span> <span class="hljs-comment"># Support `CoffeeScript.nodes(tokens)`.</span>
<span class="hljs-keyword">throw</span> helpers.updateSyntaxError err, code, options.filename</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-9">&#x00a7;</a>
</div>
<p>Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.</p>
<p>If <code>options.sourceMap</code> is specified, then <code>options.filename</code> must also be
specified. All options that can be passed to <code>SourceMap#generate</code> may also
be passed here.</p>
<p>This returns a javascript string, unless <code>options.sourceMap</code> is passed,
in which case this returns a <code>{js, v3SourceMap, sourceMap}</code>
object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for
doing programmatic lookups.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.compile = compile = withPrettyErrors (code, options = {}) -&gt;</pre></div></div>
</li>
<li id="section-10">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-10">&#x00a7;</a>
</div>
<p>Clone <code>options</code>, to avoid mutating the <code>options</code> object passed in.</p>
</div>
<div class="content"><div class='highlight'><pre> options = <span class="hljs-built_in">Object</span>.assign {}, options
generateSourceMap = options.sourceMap <span class="hljs-keyword">or</span> options.inlineMap <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> options.filename?
filename = options.filename <span class="hljs-keyword">or</span> helpers.anonymousFileName()
checkShebangLine filename, code
map = <span class="hljs-keyword">new</span> SourceMap <span class="hljs-keyword">if</span> generateSourceMap
tokens = lexer.tokenize code, options</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-11">&#x00a7;</a>
</div>
<p>Pass a list of referenced variables, so that generated variables wont get
the same name.</p>
</div>
<div class="content"><div class='highlight'><pre> options.referencedVars = (
token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;IDENTIFIER&#x27;</span>
)</pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-12">&#x00a7;</a>
</div>
<p>Check for import or export; if found, force bare mode.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> options.bare? <span class="hljs-keyword">and</span> options.bare <span class="hljs-keyword">is</span> <span class="hljs-literal">yes</span>
<span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens
<span class="hljs-keyword">if</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;IMPORT&#x27;</span>, <span class="hljs-string">&#x27;EXPORT&#x27;</span>]
options.bare = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">break</span>
nodes = parser.parse tokens</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-13">&#x00a7;</a>
</div>
<p>If all that was requested was a POJO representation of the nodes, e.g.
the abstract syntax tree (AST), we can stop now and just return that
(after fixing the location data for the root/<code>File</code>»<code>Program</code> node,
which mightve gotten misaligned from the original source due to the
<code>clean</code> function in the lexer).</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> options.ast
nodes.allCommentTokens = helpers.extractAllCommentTokens tokens
sourceCodeNumberOfLines = (code.match(<span class="hljs-regexp">/\r?\n/g</span>) <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;&#x27;</span>).length + <span class="hljs-number">1</span>
sourceCodeLastLine = <span class="hljs-regexp">/.*$/</span>.exec(code)[<span class="hljs-number">0</span>] <span class="hljs-comment"># `.*` matches all but line break characters.</span>
ast = nodes.ast options
range = [<span class="hljs-number">0</span>, code.length]
ast.start = ast.program.start = range[<span class="hljs-number">0</span>]
ast.end = ast.program.end = range[<span class="hljs-number">1</span>]
ast.range = ast.program.range = range
ast.loc.start = ast.program.loc.start = {line: <span class="hljs-number">1</span>, column: <span class="hljs-number">0</span>}
ast.loc.end.line = ast.program.loc.end.line = sourceCodeNumberOfLines
ast.loc.end.column = ast.program.loc.end.column = sourceCodeLastLine.length
ast.tokens = tokens
<span class="hljs-keyword">return</span> ast
fragments = nodes.compileToFragments options
currentLine = <span class="hljs-number">0</span>
currentLine += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> options.header
currentLine += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> options.shiftLine
currentColumn = <span class="hljs-number">0</span>
js = <span class="hljs-string">&quot;&quot;</span>
<span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-14">&#x00a7;</a>
</div>
<p>Update the sourcemap with data from each fragment.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> generateSourceMap</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-15">&#x00a7;</a>
</div>
<p>Do not include empty, whitespace, or semicolon-only fragments.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.locationData <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-regexp">/^[;\s]*$/</span>.test fragment.code
map.add(
[fragment.locationData.first_line, fragment.locationData.first_column]
[currentLine, currentColumn]
{noReplace: <span class="hljs-literal">true</span>})
newLines = helpers.count fragment.code, <span class="hljs-string">&quot;\n&quot;</span>
currentLine += newLines
<span class="hljs-keyword">if</span> newLines
currentColumn = fragment.code.length - (fragment.code.lastIndexOf(<span class="hljs-string">&quot;\n&quot;</span>) + <span class="hljs-number">1</span>)
<span class="hljs-keyword">else</span>
currentColumn += fragment.code.length</pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-16">&#x00a7;</a>
</div>
<p>Copy the code from each fragment into the final JavaScript.</p>
</div>
<div class="content"><div class='highlight'><pre> js += fragment.code
<span class="hljs-keyword">if</span> options.header
header = <span class="hljs-string">&quot;Generated by CoffeeScript <span class="hljs-subst">#{@VERSION}</span>&quot;</span>
js = <span class="hljs-string">&quot;// <span class="hljs-subst">#{header}</span>\n<span class="hljs-subst">#{js}</span>&quot;</span>
<span class="hljs-keyword">if</span> generateSourceMap
v3SourceMap = map.generate options, code
<span class="hljs-keyword">if</span> options.transpile
<span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> options.transpile <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;object&#x27;</span></pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-17">&#x00a7;</a>
</div>
<p>This only happens if run via the Node API and <code>transpile</code> is set to
something other than an object.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span> <span class="hljs-string">&#x27;The transpile option must be given an object with options to pass to Babel&#x27;</span></pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-18">&#x00a7;</a>
</div>
<p>Get the reference to Babel that we have been passed if this compiler
is run via the CLI or Node API.</p>
</div>
<div class="content"><div class='highlight'><pre> transpiler = options.transpile.transpile
<span class="hljs-keyword">delete</span> options.transpile.transpile
transpilerOptions = <span class="hljs-built_in">Object</span>.assign {}, options.transpile</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-19">&#x00a7;</a>
</div>
<p>See <a href="https://github.com/babel/babel/issues/827#issuecomment-77573107">https://github.com/babel/babel/issues/827#issuecomment-77573107</a>:
Babel can take a v3 source map object as input in <code>inputSourceMap</code>
and it will return an <em>updated</em> v3 source map object in its output.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> transpilerOptions.inputSourceMap?
transpilerOptions.inputSourceMap = v3SourceMap
transpilerOutput = transpiler js, transpilerOptions
js = transpilerOutput.code
<span class="hljs-keyword">if</span> v3SourceMap <span class="hljs-keyword">and</span> transpilerOutput.map
v3SourceMap = transpilerOutput.map
<span class="hljs-keyword">if</span> options.inlineMap
encoded = base64encode <span class="hljs-built_in">JSON</span>.stringify v3SourceMap
sourceMapDataURI = <span class="hljs-string">&quot;//# sourceMappingURL=data:application/json;base64,<span class="hljs-subst">#{encoded}</span>&quot;</span>
sourceURL = <span class="hljs-string">&quot;//# sourceURL=<span class="hljs-subst">#{filename}</span>&quot;</span>
js = <span class="hljs-string">&quot;<span class="hljs-subst">#{js}</span>\n<span class="hljs-subst">#{sourceMapDataURI}</span>\n<span class="hljs-subst">#{sourceURL}</span>&quot;</span>
registerCompiled filename, code, map
<span class="hljs-keyword">if</span> options.sourceMap
{
js
sourceMap: map
v3SourceMap: <span class="hljs-built_in">JSON</span>.stringify v3SourceMap, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>
}
<span class="hljs-keyword">else</span>
js</pre></div></div>
</li>
<li id="section-20">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-20">&#x00a7;</a>
</div>
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.tokens = withPrettyErrors (code, options) -&gt;
lexer.tokenize code, options</pre></div></div>
</li>
<li id="section-21">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-21">&#x00a7;</a>
</div>
<p>Parse a string of CoffeeScript code or an array of lexed tokens, and
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
or traverse it by using <code>.traverseChildren()</code> with a callback.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.nodes = withPrettyErrors (source, options) -&gt;
source = lexer.tokenize source, options <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> source <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;string&#x27;</span>
parser.parse source</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-22">&#x00a7;</a>
</div>
<p>This file used to export these methods; leave stubs that throw warnings
instead. These methods have been moved into <code>index.coffee</code> to provide
separate entrypoints for Node and non-Node environments, so that static
analysis tools dont choke on Node packages when compiling for a non-Node
environment.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.run = <span class="hljs-built_in">exports</span>.<span class="hljs-built_in">eval</span> = <span class="hljs-built_in">exports</span>.register = <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span> <span class="hljs-string">&#x27;require index.coffee, not this file&#x27;</span></pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-23">&#x00a7;</a>
</div>
<p>Instantiate a Lexer for our use here.</p>
</div>
<div class="content"><div class='highlight'><pre>lexer = <span class="hljs-keyword">new</span> Lexer</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-24">&#x00a7;</a>
</div>
<p>The real Lexer produces a generic stream of tokens. This object provides a
thin wrapper around it, compatible with the Jison API. We can then pass it
directly as a “Jison lexer.”</p>
</div>
<div class="content"><div class='highlight'><pre>parser.lexer =
yylloc:
range: []
options:
ranges: <span class="hljs-literal">yes</span>
lex: <span class="hljs-function">-&gt;</span>
token = parser.tokens[@pos++]
<span class="hljs-keyword">if</span> token
[tag, @yytext, @yylloc] = token
parser.errorToken = token.origin <span class="hljs-keyword">or</span> token
@yylineno = @yylloc.first_line
<span class="hljs-keyword">else</span>
tag = <span class="hljs-string">&#x27;&#x27;</span>
tag
setInput: <span class="hljs-function"><span class="hljs-params">(tokens)</span> -&gt;</span>
parser.tokens = tokens
@pos = <span class="hljs-number">0</span>
upcomingInput: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;&#x27;</span></pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-25">&#x00a7;</a>
</div>
<p>Make all the AST nodes visible to the parser.</p>
</div>
<div class="content"><div class='highlight'><pre>parser.yy = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./nodes&#x27;</span></pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-26">&#x00a7;</a>
</div>
<p>Override Jisons default error handling function.</p>
</div>
<div class="content"><div class='highlight'><pre>parser.yy.parseError = <span class="hljs-function"><span class="hljs-params">(message, {token})</span> -&gt;</span></pre></div></div>
</li>
<li id="section-27">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-27">&#x00a7;</a>
</div>
<p>Disregard Jisons message, it contains redundant line number information.
Disregard the token, we take its value directly from the lexer in case
the error is caused by a generated token which might refer to its origin.</p>
</div>
<div class="content"><div class='highlight'><pre> {errorToken, tokens} = parser
[errorTag, errorText, errorLoc] = errorToken
errorText = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> errorToken <span class="hljs-keyword">is</span> tokens[tokens.length - <span class="hljs-number">1</span>]
<span class="hljs-string">&#x27;end of input&#x27;</span>
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;INDENT&#x27;</span>, <span class="hljs-string">&#x27;OUTDENT&#x27;</span>]
<span class="hljs-string">&#x27;indentation&#x27;</span>
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;IDENTIFIER&#x27;</span>, <span class="hljs-string">&#x27;NUMBER&#x27;</span>, <span class="hljs-string">&#x27;INFINITY&#x27;</span>, <span class="hljs-string">&#x27;STRING&#x27;</span>, <span class="hljs-string">&#x27;STRING_START&#x27;</span>, <span class="hljs-string">&#x27;REGEX&#x27;</span>, <span class="hljs-string">&#x27;REGEX_START&#x27;</span>]
errorTag.replace(<span class="hljs-regexp">/_START$/</span>, <span class="hljs-string">&#x27;&#x27;</span>).toLowerCase()
<span class="hljs-keyword">else</span>
helpers.nameWhitespaceCharacter errorText</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-28">&#x00a7;</a>
</div>
<p>The second argument has a <code>loc</code> property, which should have the location
data for this token. Unfortunately, Jison seems to send an outdated <code>loc</code>
(from the previous token), so we take the location information directly
from the lexer.</p>
</div>
<div class="content"><div class='highlight'><pre> helpers.throwSyntaxError <span class="hljs-string">&quot;unexpected <span class="hljs-subst">#{errorText}</span>&quot;</span>, errorLoc
<span class="hljs-built_in">exports</span>.patchStackTrace = <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-29">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-29">&#x00a7;</a>
</div>
<p>Based on <a href="http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js">http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js</a>
Modified to handle sourceMap</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">formatSourcePosition</span> = <span class="hljs-params">(frame, getSourceMapping)</span> -&gt;</span>
filename = <span class="hljs-literal">undefined</span>
fileLocation = <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">if</span> frame.isNative()
fileLocation = <span class="hljs-string">&quot;native&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> frame.isEval()
filename = frame.getScriptNameOrSourceURL()
fileLocation = <span class="hljs-string">&quot;<span class="hljs-subst">#{frame.getEvalOrigin()}</span>, &quot;</span> <span class="hljs-keyword">unless</span> filename
<span class="hljs-keyword">else</span>
filename = frame.getFileName()
filename <span class="hljs-keyword">or</span>= <span class="hljs-string">&quot;&lt;anonymous&gt;&quot;</span>
line = frame.getLineNumber()
column = frame.getColumnNumber()</pre></div></div>
</li>
<li id="section-30">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-30">&#x00a7;</a>
</div>
<p>Check for a sourceMap position</p>
</div>
<div class="content"><div class='highlight'><pre> source = getSourceMapping filename, line, column
fileLocation =
<span class="hljs-keyword">if</span> source
<span class="hljs-string">&quot;<span class="hljs-subst">#{filename}</span>:<span class="hljs-subst">#{source[<span class="hljs-number">0</span>]}</span>:<span class="hljs-subst">#{source[<span class="hljs-number">1</span>]}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{filename}</span>:<span class="hljs-subst">#{line}</span>:<span class="hljs-subst">#{column}</span>&quot;</span>
functionName = frame.getFunctionName()
isConstructor = frame.isConstructor()
isMethodCall = <span class="hljs-keyword">not</span> (frame.isToplevel() <span class="hljs-keyword">or</span> isConstructor)
<span class="hljs-keyword">if</span> isMethodCall
methodName = frame.getMethodName()
typeName = frame.getTypeName()
<span class="hljs-keyword">if</span> functionName
tp = <span class="hljs-keyword">as</span> = <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">if</span> typeName <span class="hljs-keyword">and</span> functionName.indexOf typeName
tp = <span class="hljs-string">&quot;<span class="hljs-subst">#{typeName}</span>.&quot;</span>
<span class="hljs-keyword">if</span> methodName <span class="hljs-keyword">and</span> functionName.indexOf(<span class="hljs-string">&quot;.<span class="hljs-subst">#{methodName}</span>&quot;</span>) <span class="hljs-keyword">isnt</span> functionName.length - methodName.length - <span class="hljs-number">1</span>
<span class="hljs-keyword">as</span> = <span class="hljs-string">&quot; [as <span class="hljs-subst">#{methodName}</span>]&quot;</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{tp}</span><span class="hljs-subst">#{functionName}</span><span class="hljs-subst">#{<span class="hljs-keyword">as</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{typeName}</span>.<span class="hljs-subst">#{methodName <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;&lt;anonymous&gt;&#x27;</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)&quot;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> isConstructor
<span class="hljs-string">&quot;new <span class="hljs-subst">#{functionName <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;&lt;anonymous&gt;&#x27;</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)&quot;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> functionName
<span class="hljs-string">&quot;<span class="hljs-subst">#{functionName}</span> (<span class="hljs-subst">#{fileLocation}</span>)&quot;</span>
<span class="hljs-keyword">else</span>
fileLocation
<span class="hljs-function">
<span class="hljs-title">getSourceMapping</span> = <span class="hljs-params">(filename, line, column)</span> -&gt;</span>
sourceMap = getSourceMap filename, line, column
answer = sourceMap.sourceLocation [line - <span class="hljs-number">1</span>, column - <span class="hljs-number">1</span>] <span class="hljs-keyword">if</span> sourceMap?
<span class="hljs-keyword">if</span> answer? <span class="hljs-keyword">then</span> [answer[<span class="hljs-number">0</span>] + <span class="hljs-number">1</span>, answer[<span class="hljs-number">1</span>] + <span class="hljs-number">1</span>] <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-31">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-31">&#x00a7;</a>
</div>
<p>Based on <a href="http://goo.gl/ZTx1p">michaelficarra/CoffeeScriptRedux</a>
NodeJS / V8 have no support for transforming positions in stack traces using
sourceMap, so we must monkey-patch Error to display CoffeeScript source
positions.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-built_in">Error</span>.prepareStackTrace = <span class="hljs-function"><span class="hljs-params">(err, stack)</span> -&gt;</span>
frames = <span class="hljs-keyword">for</span> frame <span class="hljs-keyword">in</span> stack</pre></div></div>
</li>
<li id="section-32">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-32">&#x00a7;</a>
</div>
<p>Dont display stack frames deeper than <code>CoffeeScript.run</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> frame.getFunction() <span class="hljs-keyword">is</span> <span class="hljs-built_in">exports</span>.run
<span class="hljs-string">&quot; at <span class="hljs-subst">#{formatSourcePosition frame, getSourceMapping}</span>&quot;</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{err.toString()}</span>\n<span class="hljs-subst">#{frames.join <span class="hljs-string">&#x27;\n&#x27;</span>}</span>\n&quot;</span>
<span class="hljs-function">
<span class="hljs-title">checkShebangLine</span> = <span class="hljs-params">(file, input)</span> -&gt;</span>
firstLine = input.split(<span class="hljs-regexp">/$/m</span>, <span class="hljs-number">1</span>)[<span class="hljs-number">0</span>]
rest = firstLine?.match(<span class="hljs-regexp">/^#!\s*([^\s]+\s*)(.*)/</span>)
args = rest?[<span class="hljs-number">2</span>]?.split(<span class="hljs-regexp">/\s/</span>).filter (s) -&gt; s <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">if</span> args?.length &gt; <span class="hljs-number">1</span>
console.error <span class="hljs-string">&#x27;&#x27;&#x27;
The script to be run begins with a shebang line with more than one
argument. This script will fail on platforms such as Linux which only
allow a single argument.
&#x27;&#x27;&#x27;</span>
console.error <span class="hljs-string">&quot;The shebang line was: &#x27;<span class="hljs-subst">#{firstLine}</span>&#x27; in file &#x27;<span class="hljs-subst">#{file}</span>&#x27;&quot;</span>
console.error <span class="hljs-string">&quot;The arguments were: <span class="hljs-subst">#{<span class="hljs-built_in">JSON</span>.stringify args}</span>&quot;</span></pre></div></div>
</li>
</ul>
</div>
</body>
</html>