mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
982 lines
44 KiB
HTML
982 lines
44 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<title>coffee-script.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 …</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="coffee-script.html">
|
||
coffee-script.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>coffee-script.coffee</h1>
|
||
</div>
|
||
</li>
|
||
|
||
|
||
|
||
<li id="section-1">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-1">¶</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>
|
||
fs = <span class="hljs-built_in">require</span> <span class="hljs-string">'fs'</span>
|
||
vm = <span class="hljs-built_in">require</span> <span class="hljs-string">'vm'</span>
|
||
path = <span class="hljs-built_in">require</span> <span class="hljs-string">'path'</span>
|
||
{Lexer} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./lexer'</span>
|
||
{parser} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./parser'</span>
|
||
helpers = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span>
|
||
SourceMap = <span class="hljs-built_in">require</span> <span class="hljs-string">'./sourcemap'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-2">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-2">¶</a>
|
||
</div>
|
||
<p>Require <code>package.json</code>, which is two levels above this file, as this file is
|
||
evaluated from <code>lib/coffee-script</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>packageJson = <span class="hljs-built_in">require</span> <span class="hljs-string">'../../package.json'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-3">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-3">¶</a>
|
||
</div>
|
||
<p>The current CoffeeScript version number.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.VERSION = packageJson.version
|
||
|
||
exports.FILE_EXTENSIONS = [<span class="hljs-string">'.coffee'</span>, <span class="hljs-string">'.litcoffee'</span>, <span class="hljs-string">'.coffee.md'</span>]</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-4">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-4">¶</a>
|
||
</div>
|
||
<p>Expose helpers for testing.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.helpers = helpers</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-5">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-5">¶</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> -></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">'function'</span>
|
||
<span class="hljs-keyword">new</span> Buffer(src).toString(<span class="hljs-string">'base64'</span>)
|
||
<span class="hljs-keyword">when</span> <span class="hljs-keyword">typeof</span> btoa <span class="hljs-keyword">is</span> <span class="hljs-string">'function'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-6">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-6">¶</a>
|
||
</div>
|
||
<p>The contents of a <code><script></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 encodeURIComponent(src).replace <span class="hljs-regexp">/%([0-9A-F]{2})/g</span>, <span class="hljs-function"><span class="hljs-params">(match, p1)</span> -></span>
|
||
String.fromCharCode <span class="hljs-string">'0x'</span> + p1
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error(<span class="hljs-string">'Unable to base64 encode inline sourcemap.'</span>)</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-7">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-7">¶</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> -></span>
|
||
(code, options = {}) ->
|
||
<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">'string'</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-8">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-8">¶</a>
|
||
</div>
|
||
<p>For each compiled file, save its source in memory in case we need to
|
||
recompile it later. We might need to recompile if the first compilation
|
||
didn’t create a source map (faster) but something went wrong and we need
|
||
a stack trace. Assuming that most of the time, code isn’t throwing
|
||
exceptions, it’s probably more efficient to compile twice only when we
|
||
need a stack trace, rather than always generating a source map even when
|
||
it’s not likely to be used. Save in form of <code>filename</code>: <code>(source)</code></p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>sources = {}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-9">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-9">¶</a>
|
||
</div>
|
||
<p>Also save source maps if generated, in form of <code>filename</code>: <code>(source map)</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>sourceMaps = {}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-10">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-10">¶</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>exports.compile = compile = withPrettyErrors (code, options) ->
|
||
{merge, extend} = helpers
|
||
options = extend {}, options</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-11">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-11">¶</a>
|
||
</div>
|
||
<p>Always generate a source map if no filename is passed in, since without a
|
||
a filename we have no way to retrieve this source later in the event that
|
||
we need to recompile it to get a source map for <code>prepareStackTrace</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> 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> <span class="hljs-string">'<anonymous>'</span>
|
||
|
||
sources[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-12">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-12">¶</a>
|
||
</div>
|
||
<p>Pass a list of referenced variables, so that generated variables won’t 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">'IDENTIFIER'</span>
|
||
)</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-13">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-13">¶</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">'IMPORT'</span>, <span class="hljs-string">'EXPORT'</span>]
|
||
options.bare = <span class="hljs-literal">yes</span>
|
||
<span class="hljs-keyword">break</span>
|
||
|
||
fragments = parser.parse(tokens).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">""</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="pilwrap ">
|
||
<a class="pilcrow" href="#section-14">¶</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="pilwrap ">
|
||
<a class="pilcrow" href="#section-15">¶</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">"\n"</span>
|
||
currentLine += newLines
|
||
<span class="hljs-keyword">if</span> newLines
|
||
currentColumn = fragment.code.length - (fragment.code.lastIndexOf(<span class="hljs-string">"\n"</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="pilwrap ">
|
||
<a class="pilcrow" href="#section-16">¶</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">"Generated by CoffeeScript <span class="hljs-subst">#{@VERSION}</span>"</span>
|
||
js = <span class="hljs-string">"// <span class="hljs-subst">#{header}</span>\n<span class="hljs-subst">#{js}</span>"</span>
|
||
|
||
<span class="hljs-keyword">if</span> generateSourceMap
|
||
v3SourceMap = map.generate(options, code)
|
||
sourceMaps[filename] = map
|
||
|
||
<span class="hljs-keyword">if</span> options.inlineMap
|
||
encoded = base64encode JSON.stringify v3SourceMap
|
||
sourceMapDataURI = <span class="hljs-string">"//# sourceMappingURL=data:application/json;base64,<span class="hljs-subst">#{encoded}</span>"</span>
|
||
sourceURL = <span class="hljs-string">"//# sourceURL=<span class="hljs-subst">#{options.filename ? <span class="hljs-string">'coffeescript'</span>}</span>"</span>
|
||
js = <span class="hljs-string">"<span class="hljs-subst">#{js}</span>\n<span class="hljs-subst">#{sourceMapDataURI}</span>\n<span class="hljs-subst">#{sourceURL}</span>"</span>
|
||
|
||
<span class="hljs-keyword">if</span> options.sourceMap
|
||
{
|
||
js
|
||
sourceMap: map
|
||
v3SourceMap: JSON.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-17">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-17">¶</a>
|
||
</div>
|
||
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.tokens = withPrettyErrors (code, options) ->
|
||
lexer.tokenize code, options</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-18">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-18">¶</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>exports.nodes = withPrettyErrors (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">'string'</span>
|
||
parser.parse lexer.tokenize source, options
|
||
<span class="hljs-keyword">else</span>
|
||
parser.parse source</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-19">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-19">¶</a>
|
||
</div>
|
||
<p>Compile and execute a string of CoffeeScript (on the server), correctly
|
||
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.run = <span class="hljs-function"><span class="hljs-params">(code, options = {})</span> -></span>
|
||
mainModule = <span class="hljs-built_in">require</span>.main</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-20">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-20">¶</a>
|
||
</div>
|
||
<p>Set the filename.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> mainModule.filename = process.argv[<span class="hljs-number">1</span>] =
|
||
<span class="hljs-keyword">if</span> options.filename <span class="hljs-keyword">then</span> fs.realpathSync(options.filename) <span class="hljs-keyword">else</span> <span class="hljs-string">'<anonymous>'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-21">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-21">¶</a>
|
||
</div>
|
||
<p>Clear the module cache.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> mainModule.moduleCache <span class="hljs-keyword">and</span>= {}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-22">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-22">¶</a>
|
||
</div>
|
||
<p>Assign paths for node_modules loading</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> dir = <span class="hljs-keyword">if</span> options.filename?
|
||
path.dirname fs.realpathSync options.filename
|
||
<span class="hljs-keyword">else</span>
|
||
fs.realpathSync <span class="hljs-string">'.'</span>
|
||
mainModule.paths = <span class="hljs-built_in">require</span>(<span class="hljs-string">'module'</span>)._nodeModulePaths dir</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-23">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-23">¶</a>
|
||
</div>
|
||
<p>Compile.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> helpers.isCoffee(mainModule.filename) <span class="hljs-keyword">or</span> <span class="hljs-built_in">require</span>.extensions
|
||
answer = compile code, options
|
||
code = answer.js ? answer
|
||
|
||
mainModule._compile code, mainModule.filename</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-24">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-24">¶</a>
|
||
</div>
|
||
<p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||
The CoffeeScript REPL uses this to run the input.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.eval = <span class="hljs-function"><span class="hljs-params">(code, options = {})</span> -></span>
|
||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> code = code.trim()
|
||
createContext = vm.Script.createContext ? vm.createContext
|
||
|
||
isContext = vm.isContext ? (ctx) ->
|
||
options.sandbox <span class="hljs-keyword">instanceof</span> createContext().constructor
|
||
|
||
<span class="hljs-keyword">if</span> createContext
|
||
<span class="hljs-keyword">if</span> options.sandbox?
|
||
<span class="hljs-keyword">if</span> isContext options.sandbox
|
||
sandbox = options.sandbox
|
||
<span class="hljs-keyword">else</span>
|
||
sandbox = createContext()
|
||
sandbox[k] = v <span class="hljs-keyword">for</span> own k, v <span class="hljs-keyword">of</span> options.sandbox
|
||
sandbox.<span class="hljs-built_in">global</span> = sandbox.root = sandbox.GLOBAL = sandbox
|
||
<span class="hljs-keyword">else</span>
|
||
sandbox = <span class="hljs-built_in">global</span>
|
||
sandbox.__filename = options.filename || <span class="hljs-string">'eval'</span>
|
||
sandbox.__dirname = path.dirname sandbox.__filename</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-25">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-25">¶</a>
|
||
</div>
|
||
<p>define module/require only if they chose not to specify their own</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> sandbox <span class="hljs-keyword">isnt</span> <span class="hljs-built_in">global</span> <span class="hljs-keyword">or</span> sandbox.<span class="hljs-built_in">module</span> <span class="hljs-keyword">or</span> sandbox.<span class="hljs-built_in">require</span>
|
||
Module = <span class="hljs-built_in">require</span> <span class="hljs-string">'module'</span>
|
||
sandbox.<span class="hljs-built_in">module</span> = _module = <span class="hljs-keyword">new</span> Module(options.modulename || <span class="hljs-string">'eval'</span>)
|
||
sandbox.<span class="hljs-built_in">require</span> = _require = <span class="hljs-function"><span class="hljs-params">(path)</span> -></span> Module._load path, _module, <span class="hljs-literal">true</span>
|
||
_module.filename = sandbox.__filename
|
||
<span class="hljs-keyword">for</span> r <span class="hljs-keyword">in</span> Object.getOwnPropertyNames <span class="hljs-built_in">require</span> <span class="hljs-keyword">when</span> r <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'paths'</span>, <span class="hljs-string">'arguments'</span>, <span class="hljs-string">'caller'</span>]
|
||
_require[r] = <span class="hljs-built_in">require</span>[r]</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-26">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-26">¶</a>
|
||
</div>
|
||
<p>use the same hack node currently uses for their own REPL</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> _require.paths = _module.paths = Module._nodeModulePaths process.cwd()
|
||
_require.resolve = <span class="hljs-function"><span class="hljs-params">(request)</span> -></span> Module._resolveFilename request, _module
|
||
o = {}
|
||
o[k] = v <span class="hljs-keyword">for</span> own k, v <span class="hljs-keyword">of</span> options
|
||
o.bare = <span class="hljs-literal">on</span> <span class="hljs-comment"># ensure return value</span>
|
||
js = compile code, o
|
||
<span class="hljs-keyword">if</span> sandbox <span class="hljs-keyword">is</span> <span class="hljs-built_in">global</span>
|
||
vm.runInThisContext js
|
||
<span class="hljs-keyword">else</span>
|
||
vm.runInContext js, sandbox
|
||
|
||
exports.register = <span class="hljs-function">-></span> <span class="hljs-built_in">require</span> <span class="hljs-string">'./register'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-27">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-27">¶</a>
|
||
</div>
|
||
<p>Throw error with deprecation warning when depending upon implicit <code>require.extensions</code> registration</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">if</span> <span class="hljs-built_in">require</span>.extensions
|
||
<span class="hljs-keyword">for</span> ext <span class="hljs-keyword">in</span> @FILE_EXTENSIONS <span class="hljs-keyword">then</span> <span class="hljs-keyword">do</span> (ext) ->
|
||
<span class="hljs-built_in">require</span>.extensions[ext] ?= <span class="hljs-function">-></span>
|
||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">"""
|
||
Use CoffeeScript.register() or require the coffee-script/register module to require <span class="hljs-subst">#{ext}</span> files.
|
||
"""</span>
|
||
|
||
exports._compileFile = <span class="hljs-function"><span class="hljs-params">(filename, sourceMap = <span class="hljs-literal">no</span>, inlineMap = <span class="hljs-literal">no</span>)</span> -></span>
|
||
raw = fs.readFileSync filename, <span class="hljs-string">'utf8'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-28">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-28">¶</a>
|
||
</div>
|
||
<p>Strip the Unicode byte order mark, if this file begins with one.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> stripped = <span class="hljs-keyword">if</span> raw.charCodeAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-number">0xFEFF</span> <span class="hljs-keyword">then</span> raw.substring <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> raw
|
||
|
||
<span class="hljs-keyword">try</span>
|
||
answer = compile stripped, {
|
||
filename, sourceMap, inlineMap
|
||
sourceFiles: [filename]
|
||
literate: helpers.isLiterate filename
|
||
}
|
||
<span class="hljs-keyword">catch</span> err</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-29">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-29">¶</a>
|
||
</div>
|
||
<p>As the filename and code of a dynamically loaded file will be different
|
||
from the original file compiled with CoffeeScript.run, add that
|
||
information to error so it can be pretty-printed later.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> helpers.updateSyntaxError err, stripped, filename
|
||
|
||
answer</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-30">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-30">¶</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-31">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-31">¶</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 =
|
||
lex: <span class="hljs-function">-></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">''</span>
|
||
|
||
tag
|
||
setInput: <span class="hljs-function"><span class="hljs-params">(tokens)</span> -></span>
|
||
parser.tokens = tokens
|
||
@pos = <span class="hljs-number">0</span>
|
||
upcomingInput: <span class="hljs-function">-></span>
|
||
<span class="hljs-string">""</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-32">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-32">¶</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">'./nodes'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-33">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-33">¶</a>
|
||
</div>
|
||
<p>Override Jison’s 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> -></span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-34">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-34">¶</a>
|
||
</div>
|
||
<p>Disregard Jison’s 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">'end of input'</span>
|
||
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>]
|
||
<span class="hljs-string">'indentation'</span>
|
||
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'INFINITY'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_START'</span>]
|
||
errorTag.replace(<span class="hljs-regexp">/_START$/</span>, <span class="hljs-string">''</span>).toLowerCase()
|
||
<span class="hljs-keyword">else</span>
|
||
helpers.nameWhitespaceCharacter errorText</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-35">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-35">¶</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">"unexpected <span class="hljs-subst">#{errorText}</span>"</span>, errorLoc</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-36">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-36">¶</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> -></span>
|
||
filename = <span class="hljs-literal">undefined</span>
|
||
fileLocation = <span class="hljs-string">''</span>
|
||
|
||
<span class="hljs-keyword">if</span> frame.isNative()
|
||
fileLocation = <span class="hljs-string">"native"</span>
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-keyword">if</span> frame.isEval()
|
||
filename = frame.getScriptNameOrSourceURL()
|
||
fileLocation = <span class="hljs-string">"<span class="hljs-subst">#{frame.getEvalOrigin()}</span>, "</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">"<anonymous>"</span>
|
||
|
||
line = frame.getLineNumber()
|
||
column = frame.getColumnNumber()</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-37">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-37">¶</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">"<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>"</span>
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-string">"<span class="hljs-subst">#{filename}</span>:<span class="hljs-subst">#{line}</span>:<span class="hljs-subst">#{column}</span>"</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">''</span>
|
||
<span class="hljs-keyword">if</span> typeName <span class="hljs-keyword">and</span> functionName.indexOf typeName
|
||
tp = <span class="hljs-string">"<span class="hljs-subst">#{typeName}</span>."</span>
|
||
<span class="hljs-keyword">if</span> methodName <span class="hljs-keyword">and</span> functionName.indexOf(<span class="hljs-string">".<span class="hljs-subst">#{methodName}</span>"</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">" [as <span class="hljs-subst">#{methodName}</span>]"</span>
|
||
|
||
<span class="hljs-string">"<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>)"</span>
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-string">"<span class="hljs-subst">#{typeName}</span>.<span class="hljs-subst">#{methodName <span class="hljs-keyword">or</span> <span class="hljs-string">'<anonymous>'</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span>
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> isConstructor
|
||
<span class="hljs-string">"new <span class="hljs-subst">#{functionName <span class="hljs-keyword">or</span> <span class="hljs-string">'<anonymous>'</span>}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span>
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> functionName
|
||
<span class="hljs-string">"<span class="hljs-subst">#{functionName}</span> (<span class="hljs-subst">#{fileLocation}</span>)"</span>
|
||
<span class="hljs-keyword">else</span>
|
||
fileLocation
|
||
<span class="hljs-function">
|
||
<span class="hljs-title">getSourceMap</span> = <span class="hljs-params">(filename)</span> -></span>
|
||
<span class="hljs-keyword">if</span> sourceMaps[filename]?
|
||
sourceMaps[filename]</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-38">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-38">¶</a>
|
||
</div>
|
||
<p>CoffeeScript compiled in a browser may get compiled with <code>options.filename</code>
|
||
of <code><anonymous></code>, but the browser may request the stack trace with the
|
||
filename of the script file.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> sourceMaps[<span class="hljs-string">'<anonymous>'</span>]?
|
||
sourceMaps[<span class="hljs-string">'<anonymous>'</span>]
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> sources[filename]?
|
||
answer = compile sources[filename],
|
||
filename: filename
|
||
sourceMap: <span class="hljs-literal">yes</span>
|
||
literate: helpers.isLiterate filename
|
||
answer.sourceMap
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-literal">null</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-39">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-39">¶</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>Error.prepareStackTrace = <span class="hljs-function"><span class="hljs-params">(err, stack)</span> -></span>
|
||
<span class="hljs-function"> <span class="hljs-title">getSourceMapping</span> = <span class="hljs-params">(filename, line, column)</span> -></span>
|
||
sourceMap = getSourceMap filename
|
||
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>
|
||
|
||
frames = <span class="hljs-keyword">for</span> frame <span class="hljs-keyword">in</span> stack
|
||
<span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> frame.getFunction() <span class="hljs-keyword">is</span> exports.run
|
||
<span class="hljs-string">" at <span class="hljs-subst">#{formatSourcePosition frame, getSourceMapping}</span>"</span>
|
||
|
||
<span class="hljs-string">"<span class="hljs-subst">#{err.toString()}</span>\n<span class="hljs-subst">#{frames.join <span class="hljs-string">'\n'</span>}</span>\n"</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
</html>
|