mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
874 lines
34 KiB
HTML
874 lines
34 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">
|
|
|
|
|
|
<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="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>
|
|
</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 = require <span class="string">'fs'</span>
|
|
vm = require <span class="string">'vm'</span>
|
|
path = require <span class="string">'path'</span>
|
|
child_process = require <span class="string">'child_process'</span>
|
|
{Lexer} = require <span class="string">'./lexer'</span>
|
|
{parser} = require <span class="string">'./parser'</span>
|
|
helpers = require <span class="string">'./helpers'</span>
|
|
SourceMap = require <span class="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>The current CoffeeScript version number.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>exports.VERSION = <span class="string">'1.6.3'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-3">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-3">¶</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-4">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-4">¶</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 programatic
|
|
lookups.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>exports.compile = <span class="function"><span class="title">compile</span></span> = (code, options = {}) ->
|
|
{merge} = helpers
|
|
|
|
<span class="keyword">if</span> options.sourceMap
|
|
map = <span class="keyword">new</span> SourceMap
|
|
|
|
fragments = parser.parse(lexer.tokenize code, options).compileToFragments options
|
|
|
|
currentLine = <span class="number">0</span>
|
|
currentLine += <span class="number">1</span> <span class="keyword">if</span> options.header
|
|
currentLine += <span class="number">1</span> <span class="keyword">if</span> options.shiftLine
|
|
currentColumn = <span class="number">0</span>
|
|
js = <span class="string">""</span>
|
|
<span class="keyword">for</span> fragment <span class="keyword">in</span> fragments</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-5">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-5">¶</a>
|
|
</div>
|
|
<p>Update the sourcemap with data from each fragment
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> options.sourceMap
|
|
<span class="keyword">if</span> fragment.locationData
|
|
map.add(
|
|
[fragment.locationData.first_line, fragment.locationData.first_column]
|
|
[currentLine, currentColumn]
|
|
{noReplace: <span class="literal">true</span>})
|
|
newLines = helpers.count fragment.code, <span class="string">"\n"</span>
|
|
currentLine += newLines
|
|
currentColumn = fragment.code.length - (<span class="keyword">if</span> newLines <span class="keyword">then</span> fragment.code.lastIndexOf <span class="string">"\n"</span> <span class="keyword">else</span> <span class="number">0</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-6">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-6">¶</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="keyword">if</span> options.header
|
|
header = <span class="string">"Generated by CoffeeScript <span class="subst">#{@VERSION}</span>"</span>
|
|
js = <span class="string">"// <span class="subst">#{header}</span>\n<span class="subst">#{js}</span>"</span>
|
|
|
|
<span class="keyword">if</span> options.sourceMap
|
|
answer = {js}
|
|
answer.sourceMap = map
|
|
answer.v3SourceMap = map.generate(options, code)
|
|
answer
|
|
<span class="keyword">else</span>
|
|
js</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-7">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-7">¶</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.<span class="function"><span class="title">tokens</span></span> = (code, options) ->
|
|
lexer.tokenize code, options</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-8">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-8">¶</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.<span class="function"><span class="title">nodes</span></span> = (source, options) ->
|
|
<span class="keyword">if</span> <span class="keyword">typeof</span> source <span class="keyword">is</span> <span class="string">'string'</span>
|
|
parser.parse lexer.tokenize source, options
|
|
<span class="keyword">else</span>
|
|
parser.parse source</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-9">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-9">¶</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.<span class="function"><span class="title">run</span></span> = (code, options = {}) ->
|
|
mainModule = require.main
|
|
options.sourceMap ?= <span class="literal">true</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-10">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-10">¶</a>
|
|
</div>
|
|
<p>Set the filename.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> mainModule.filename = process.argv[<span class="number">1</span>] =
|
|
<span class="keyword">if</span> options.filename <span class="keyword">then</span> fs.realpathSync(options.filename) <span class="keyword">else</span> <span class="string">'.'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-11">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-11">¶</a>
|
|
</div>
|
|
<p>Clear the module cache.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> mainModule.moduleCache <span class="keyword">and</span>= {}</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-12">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-12">¶</a>
|
|
</div>
|
|
<p>Assign paths for node_modules loading
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> mainModule.paths = require(<span class="string">'module'</span>)._nodeModulePaths path.dirname fs.realpathSync options.filename <span class="keyword">or</span> <span class="string">'.'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-13">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-13">¶</a>
|
|
</div>
|
|
<p>Compile.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> <span class="keyword">not</span> helpers.isCoffee(mainModule.filename) <span class="keyword">or</span> require.extensions
|
|
answer = compile(code, options)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-14">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-14">¶</a>
|
|
</div>
|
|
<p>Attach sourceMap object to sourceMaps[options.filename] so that
|
|
it is accessible by Error.prepareStackTrace.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">do</span> patchStackTrace
|
|
sourceMaps[mainModule.filename] = answer.sourceMap
|
|
mainModule._compile answer.js, mainModule.filename
|
|
<span class="keyword">else</span>
|
|
mainModule._compile code, mainModule.filename</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-15">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-15">¶</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.<span class="function"><span class="title">eval</span></span> = (code, options = {}) ->
|
|
<span class="keyword">return</span> <span class="keyword">unless</span> code = code.trim()
|
|
Script = vm.Script
|
|
<span class="keyword">if</span> Script
|
|
<span class="keyword">if</span> options.sandbox?
|
|
<span class="keyword">if</span> options.sandbox <span class="keyword">instanceof</span> Script.createContext().constructor
|
|
sandbox = options.sandbox
|
|
<span class="keyword">else</span>
|
|
sandbox = Script.createContext()
|
|
sandbox[k] = v <span class="keyword">for</span> own k, v <span class="keyword">of</span> options.sandbox
|
|
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
|
|
<span class="keyword">else</span>
|
|
sandbox = global
|
|
sandbox.__filename = options.filename || <span class="string">'eval'</span>
|
|
sandbox.__dirname = path.dirname sandbox.__filename</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-16">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-16">¶</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="keyword">unless</span> sandbox <span class="keyword">isnt</span> global <span class="keyword">or</span> sandbox.module <span class="keyword">or</span> sandbox.require
|
|
Module = require <span class="string">'module'</span>
|
|
sandbox.module = _module = <span class="keyword">new</span> Module(options.modulename || <span class="string">'eval'</span>)
|
|
sandbox.require = <span class="function"><span class="title">_require</span></span> = (path) -> Module._load path, _module, <span class="literal">true</span>
|
|
_module.filename = sandbox.__filename
|
|
_require[r] = require[r] <span class="keyword">for</span> r <span class="keyword">in</span> Object.getOwnPropertyNames require <span class="keyword">when</span> r <span class="keyword">isnt</span> <span class="string">'paths'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-17">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-17">¶</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.<span class="function"><span class="title">resolve</span></span> = (request) -> Module._resolveFilename request, _module
|
|
o = {}
|
|
o[k] = v <span class="keyword">for</span> own k, v <span class="keyword">of</span> options
|
|
o.bare = <span class="literal">on</span> <span class="comment"># ensure return value</span>
|
|
js = compile code, o
|
|
<span class="keyword">if</span> sandbox <span class="keyword">is</span> global
|
|
vm.runInThisContext js
|
|
<span class="keyword">else</span>
|
|
vm.runInContext js, sandbox</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-18">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-18">¶</a>
|
|
</div>
|
|
<p>Load and run a CoffeeScript file for Node, stripping any <code>BOM</code>s.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">loadFile</span></span> = (module, filename) ->
|
|
raw = fs.readFileSync filename, <span class="string">'utf8'</span>
|
|
stripped = <span class="keyword">if</span> raw.charCodeAt(<span class="number">0</span>) <span class="keyword">is</span> <span class="number">0xFEFF</span> <span class="keyword">then</span> raw.substring <span class="number">1</span> <span class="keyword">else</span> raw
|
|
answer = compile(stripped, {filename, sourceMap: <span class="literal">true</span>, literate: helpers.isLiterate filename})
|
|
sourceMaps[filename] = answer.sourceMap
|
|
module._compile answer.js, filename</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-19">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-19">¶</a>
|
|
</div>
|
|
<p>If the installed version of Node supports <code>require.extensions</code>, register
|
|
CoffeeScript as an extension.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> require.extensions
|
|
<span class="keyword">for</span> ext <span class="keyword">in</span> [<span class="string">'.coffee'</span>, <span class="string">'.litcoffee'</span>, <span class="string">'.coffee.md'</span>]
|
|
require.extensions[ext] = loadFile</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-20">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-20">¶</a>
|
|
</div>
|
|
<p>Patch Node's module loader to be able to handle mult-dot extensions.
|
|
This is a horrible thing that should not be required. Perhaps, one day,
|
|
when a truly benevolent dictator comes to rule over the Republik of Node,
|
|
it won't be.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> Module = require <span class="string">'module'</span>
|
|
|
|
<span class="function"><span class="title">findExtension</span></span> = (filename) ->
|
|
extensions = path.basename(filename).split <span class="string">'.'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-21">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-21">¶</a>
|
|
</div>
|
|
<p>Remove the initial dot from dotfiles.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> extensions.shift() <span class="keyword">if</span> extensions[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">''</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-22">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-22">¶</a>
|
|
</div>
|
|
<p>Start with the longest possible extension and work our way shortwards.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">while</span> extensions.shift()
|
|
curExtension = <span class="string">'.'</span> + extensions.join <span class="string">'.'</span>
|
|
<span class="keyword">return</span> curExtension <span class="keyword">if</span> Module._extensions[curExtension]
|
|
<span class="string">'.js'</span>
|
|
|
|
Module::<span class="function"><span class="title">load</span></span> = (filename) ->
|
|
<span class="property">@filename</span> = filename
|
|
<span class="property">@paths</span> = Module._nodeModulePaths path.dirname filename
|
|
extension = findExtension filename
|
|
Module._extensions[extension](<span class="keyword">this</span>, filename)
|
|
<span class="property">@loaded</span> = <span class="literal">true</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-23">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-23">¶</a>
|
|
</div>
|
|
<p>If we're on Node, patch <code>child_process.fork</code> so that Coffee scripts are able
|
|
to fork both CoffeeScript files, and JavaScript files, directly.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="keyword">if</span> child_process
|
|
{fork} = child_process
|
|
child_process.<span class="function"><span class="title">fork</span></span> = (path, args = [], options = {}) ->
|
|
execPath = <span class="keyword">if</span> helpers.isCoffee(path) <span class="keyword">then</span> <span class="string">'coffee'</span> <span class="keyword">else</span> <span class="literal">null</span>
|
|
<span class="keyword">if</span> <span class="keyword">not</span> Array.isArray args
|
|
args = []
|
|
options = args <span class="keyword">or</span> {}
|
|
options.execPath <span class="keyword">or</span>= execPath
|
|
fork path, args, options</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-24">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-24">¶</a>
|
|
</div>
|
|
<p>Instantiate a Lexer for our use here.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>lexer = <span class="keyword">new</span> Lexer</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-25">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-25">¶</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: ->
|
|
token = <span class="property">@tokens</span>[<span class="property">@pos</span>++]
|
|
<span class="keyword">if</span> token
|
|
[tag, <span class="property">@yytext</span>, <span class="property">@yylloc</span>] = token
|
|
<span class="property">@yylineno</span> = <span class="property">@yylloc</span>.first_line
|
|
<span class="keyword">else</span>
|
|
tag = <span class="string">''</span>
|
|
|
|
tag
|
|
setInput: (<span class="property">@tokens</span>) ->
|
|
<span class="property">@pos</span> = <span class="number">0</span>
|
|
upcomingInput: ->
|
|
<span class="string">""</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-26">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-26">¶</a>
|
|
</div>
|
|
<p>Make all the AST nodes visible to the parser.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>parser.yy = require <span class="string">'./nodes'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-27">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-27">¶</a>
|
|
</div>
|
|
<p>Override Jison's default error handling function.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>parser.yy.<span class="function"><span class="title">parseError</span></span> = (message, {token}) -></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-28">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-28">¶</a>
|
|
</div>
|
|
<p>Disregard Jison's message, it contains redundant line numer information.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> message = <span class="string">"unexpected <span class="subst">#{<span class="keyword">if</span> token <span class="keyword">is</span> <span class="number">1</span> <span class="keyword">then</span> 'end <span class="keyword">of</span> input' <span class="keyword">else</span> token}</span>"</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-29">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-29">¶</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 message, parser.lexer.yylloc</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-30">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-30">¶</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>
|
|
patched = <span class="literal">false</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-31">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-31">¶</a>
|
|
</div>
|
|
<p>Map of filenames -> sourceMap object.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>sourceMaps = {}
|
|
|
|
<span class="function"><span class="title">patchStackTrace</span></span> = ->
|
|
<span class="keyword">return</span> <span class="keyword">if</span> patched
|
|
patched = <span class="literal">true</span>
|
|
mainModule = require.main</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-32">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-32">¶</a>
|
|
</div>
|
|
<p>(Assigning to a property of the Module object in the normal module cache is
|
|
unsuitable, because node deletes those objects from the cache if an
|
|
exception is thrown in the module body.)
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
Error.<span class="function"><span class="title">prepareStackTrace</span></span> = (err, stack) ->
|
|
sourceFiles = {}
|
|
|
|
<span class="function"><span class="title">getSourceMapping</span></span> = (filename, line, column) ->
|
|
sourceMap = sourceMaps[filename]
|
|
answer = sourceMap.sourceLocation [line - <span class="number">1</span>, column - <span class="number">1</span>] <span class="keyword">if</span> sourceMap
|
|
<span class="keyword">if</span> answer <span class="keyword">then</span> [answer[<span class="number">0</span>] + <span class="number">1</span>, answer[<span class="number">1</span>] + <span class="number">1</span>] <span class="keyword">else</span> <span class="literal">null</span>
|
|
|
|
frames = <span class="keyword">for</span> frame <span class="keyword">in</span> stack
|
|
<span class="keyword">break</span> <span class="keyword">if</span> frame.getFunction() <span class="keyword">is</span> exports.run
|
|
<span class="string">" at <span class="subst">#{formatSourcePosition frame, getSourceMapping}</span>"</span>
|
|
|
|
<span class="string">"<span class="subst">#{err.name}</span>: <span class="subst">#{err.message ? ''}</span>\n<span class="subst">#{frames.join '\n'}</span>\n"</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-33">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-33">¶</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="function"><span class="title">formatSourcePosition</span></span> = (frame, getSourceMapping) ->
|
|
fileName = <span class="literal">undefined</span>
|
|
fileLocation = <span class="string">''</span>
|
|
|
|
<span class="keyword">if</span> frame.isNative()
|
|
fileLocation = <span class="string">"native"</span>
|
|
<span class="keyword">else</span>
|
|
<span class="keyword">if</span> frame.isEval()
|
|
fileName = frame.getScriptNameOrSourceURL()
|
|
fileLocation = <span class="string">"<span class="subst">#{frame.getEvalOrigin()}</span>, "</span> <span class="keyword">unless</span> fileName
|
|
<span class="keyword">else</span>
|
|
fileName = frame.getFileName()
|
|
|
|
fileName <span class="keyword">or</span>= <span class="string">"<anonymous>"</span>
|
|
|
|
line = frame.getLineNumber()
|
|
column = frame.getColumnNumber()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-34">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-34">¶</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="keyword">if</span> source
|
|
<span class="string">"<span class="subst">#{fileName}</span>:<span class="subst">#{source[<span class="number">0</span>]}</span>:<span class="subst">#{source[<span class="number">1</span>]}</span>, <js>:<span class="subst">#{line}</span>:<span class="subst">#{column}</span>"</span>
|
|
<span class="keyword">else</span>
|
|
<span class="string">"<span class="subst">#{fileName}</span>:<span class="subst">#{line}</span>:<span class="subst">#{column}</span>"</span>
|
|
|
|
|
|
functionName = frame.getFunctionName()
|
|
isConstructor = frame.isConstructor()
|
|
isMethodCall = <span class="keyword">not</span> (frame.isToplevel() <span class="keyword">or</span> isConstructor)
|
|
|
|
<span class="keyword">if</span> isMethodCall
|
|
methodName = frame.getMethodName()
|
|
typeName = frame.getTypeName()
|
|
|
|
<span class="keyword">if</span> functionName
|
|
tp = as = <span class="string">''</span>
|
|
<span class="keyword">if</span> typeName <span class="keyword">and</span> functionName.indexOf typeName
|
|
tp = <span class="string">"<span class="subst">#{typeName}</span>."</span>
|
|
<span class="keyword">if</span> methodName <span class="keyword">and</span> functionName.indexOf(<span class="string">".<span class="subst">#{methodName}</span>"</span>) <span class="keyword">isnt</span> functionName.length - methodName.length - <span class="number">1</span>
|
|
as = <span class="string">" [as <span class="subst">#{methodName}</span>]"</span>
|
|
|
|
<span class="string">"<span class="subst">#{tp}</span><span class="subst">#{functionName}</span><span class="subst">#{as}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
|
<span class="keyword">else</span>
|
|
<span class="string">"<span class="subst">#{typeName}</span>.<span class="subst">#{methodName <span class="keyword">or</span> '<anonymous>'}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
|
<span class="keyword">else</span> <span class="keyword">if</span> isConstructor
|
|
<span class="string">"new <span class="subst">#{functionName <span class="keyword">or</span> '<anonymous>'}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
|
<span class="keyword">else</span> <span class="keyword">if</span> functionName
|
|
<span class="string">"<span class="subst">#{functionName}</span> (<span class="subst">#{fileLocation}</span>)"</span>
|
|
<span class="keyword">else</span>
|
|
fileLocation</pre></div></div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|