mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Merge remote-tracking branch 'origin/master'
Conflicts: lib/coffee-script/coffee-script.js lib/coffee-script/lexer.js lib/coffee-script/parser.js src/lexer.coffee
This commit is contained in:
commit
a1ba0a89f8
31 changed files with 613 additions and 445 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
raw
|
raw
|
||||||
presentation
|
presentation
|
||||||
test.coffee
|
test.coffee
|
||||||
|
test.litcoffee
|
||||||
parser.output
|
parser.output
|
||||||
test/fixtures/underscore
|
test/fixtures/underscore
|
||||||
test/*.js
|
test/*.js
|
||||||
|
|
|
||||||
10
Cakefile
10
Cakefile
|
|
@ -68,7 +68,7 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||||
|
|
||||||
task 'build', 'build the CoffeeScript language from source', build = (cb) ->
|
task 'build', 'build the CoffeeScript language from source', build = (cb) ->
|
||||||
files = fs.readdirSync 'src'
|
files = fs.readdirSync 'src'
|
||||||
files = ('src/' + file for file in files when file.match(/\.coffee$/))
|
files = ('src/' + file for file in files when file.match(/\.(lit)?coffee$/))
|
||||||
run ['-c', '-o', 'lib/coffee-script'].concat(files), cb
|
run ['-c', '-o', 'lib/coffee-script'].concat(files), cb
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -119,8 +119,7 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
||||||
}(this));
|
}(this));
|
||||||
"""
|
"""
|
||||||
unless process.env.MINIFY is 'false'
|
unless process.env.MINIFY is 'false'
|
||||||
{parser, uglify} = require 'uglify-js'
|
{code} = require('uglify-js').minify code, fromString: true
|
||||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code
|
|
||||||
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
||||||
console.log "built ... running browser tests:"
|
console.log "built ... running browser tests:"
|
||||||
invoke 'test:browser'
|
invoke 'test:browser'
|
||||||
|
|
@ -227,11 +226,12 @@ runTests = (CoffeeScript) ->
|
||||||
|
|
||||||
# Run every test in the `test` folder, recording failures.
|
# Run every test in the `test` folder, recording failures.
|
||||||
files = fs.readdirSync 'test'
|
files = fs.readdirSync 'test'
|
||||||
for file in files when file.match /\.coffee$/i
|
for file in files when file.match /\.(lit)?coffee$/i
|
||||||
|
literate = path.extname(file) is '.litcoffee'
|
||||||
currentFile = filename = path.join 'test', file
|
currentFile = filename = path.join 'test', file
|
||||||
code = fs.readFileSync filename
|
code = fs.readFileSync filename
|
||||||
try
|
try
|
||||||
CoffeeScript.run code.toString(), {filename}
|
CoffeeScript.run code.toString(), {filename, literate}
|
||||||
catch error
|
catch error
|
||||||
failures.push {filename, error}
|
failures.push {filename, error}
|
||||||
return !failures.length
|
return !failures.length
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,8 @@
|
||||||
The golden rule of CoffeeScript is: <i>"It's just JavaScript"</i>. The code
|
The golden rule of CoffeeScript is: <i>"It's just JavaScript"</i>. The code
|
||||||
compiles one-to-one into the equivalent JS, and there is
|
compiles one-to-one into the equivalent JS, and there is
|
||||||
no interpretation at runtime. You can use any existing JavaScript library
|
no interpretation at runtime. You can use any existing JavaScript library
|
||||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||||
readable and pretty-printed, passes through
|
readable and pretty-printed, passes through
|
||||||
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||||
without warnings, will work in every JavaScript runtime, and tends
|
without warnings, will work in every JavaScript runtime, and tends
|
||||||
to run as fast or faster than the equivalent handwritten JavaScript.
|
to run as fast or faster than the equivalent handwritten JavaScript.
|
||||||
|
|
@ -176,7 +176,7 @@ npm install -g coffee-script</pre>
|
||||||
<p>
|
<p>
|
||||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
If you'd prefer to install the latest <b>master</b> version of CoffeeScript, you
|
If you'd prefer to install the latest <b>master</b> version of CoffeeScript, you
|
||||||
can clone the CoffeeScript
|
can clone the CoffeeScript
|
||||||
|
|
@ -190,7 +190,7 @@ npm install -g coffee-script</pre>
|
||||||
npm install -g http://github.com/jashkenas/coffee-script/tarball/master</pre>
|
npm install -g http://github.com/jashkenas/coffee-script/tarball/master</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Or, if you want to install to <tt>/usr/local</tt>, and don't want to use
|
Or, if you want to install to <tt>/usr/local</tt>, and don't want to use
|
||||||
npm to manage it, open the <tt>coffee-script</tt> directory and run:
|
npm to manage it, open the <tt>coffee-script</tt> directory and run:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -288,7 +288,7 @@ sudo bin/cake install</pre>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>-b, --bare</code></td>
|
<td><code>-b, --bare</code></td>
|
||||||
<td>
|
<td>
|
||||||
Compile the JavaScript without the
|
Compile the JavaScript without the
|
||||||
<a href="#lexical_scope">top-level function safety wrapper</a>.
|
<a href="#lexical_scope">top-level function safety wrapper</a>.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -318,8 +318,9 @@ Expressions
|
||||||
<td><code>--nodejs</code></td>
|
<td><code>--nodejs</code></td>
|
||||||
<td>
|
<td>
|
||||||
The <tt>node</tt> executable has some useful options you can set,
|
The <tt>node</tt> executable has some useful options you can set,
|
||||||
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt> and <tt>--max-stack-size</tt>. Use this
|
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt>, <tt>--max-stack-size</tt>,
|
||||||
flag to forward options directly to Node.js.
|
and <tt>--expose-gc</tt>. Use this flag to forward options directly to Node.js.
|
||||||
|
To pass multiple flags, use <tt>--nodejs</tt> multiple times.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -980,11 +981,11 @@ Expressions
|
||||||
portions in CoffeeScript.
|
portions in CoffeeScript.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
Screencasts
|
Screencasts
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://coffeescript.codeschool.com">A Sip of CoffeeScript</a> is a <a href="http://www.codeschool.com">Code School Course</a>
|
<a href="http://coffeescript.codeschool.com">A Sip of CoffeeScript</a> is a <a href="http://www.codeschool.com">Code School Course</a>
|
||||||
|
|
@ -1007,9 +1008,9 @@ Expressions
|
||||||
<h2>
|
<h2>
|
||||||
Examples
|
Examples
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <a href="https://github.com/languages/coffeescript">best list of
|
The <a href="https://github.com/languages/coffeescript">best list of
|
||||||
open-source CoffeeScript examples</a> can be found on GitHub. But just
|
open-source CoffeeScript examples</a> can be found on GitHub. But just
|
||||||
to throw out few more:
|
to throw out few more:
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -1115,7 +1116,7 @@ Expressions
|
||||||
<span id="changelog" class="bookmark"></span>
|
<span id="changelog" class="bookmark"></span>
|
||||||
Change Log
|
Change Log
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b class="header" style="margin-top: 20px;">
|
<b class="header" style="margin-top: 20px;">
|
||||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.3.3...1.4.0">1.4.0</a>
|
<a href="https://github.com/jashkenas/coffee-script/compare/1.3.3...1.4.0">1.4.0</a>
|
||||||
|
|
@ -1123,7 +1124,7 @@ Expressions
|
||||||
</b>
|
</b>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
The CoffeeScript compiler now strips Microsoft's UTF-8 BOM if it
|
The CoffeeScript compiler now strips Microsoft's UTF-8 BOM if it
|
||||||
exists, allowing you to compile BOM-borked source files.
|
exists, allowing you to compile BOM-borked source files.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -1131,12 +1132,12 @@ Expressions
|
||||||
and moving from <tt>path.exists</tt> to <tt>fs.exists</tt>.
|
and moving from <tt>path.exists</tt> to <tt>fs.exists</tt>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Small tweaks to splat compilation, backticks, slicing, and the
|
Small tweaks to splat compilation, backticks, slicing, and the
|
||||||
error for duplicate keys in object literals.
|
error for duplicate keys in object literals.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b class="header" style="margin-top: 20px;">
|
<b class="header" style="margin-top: 20px;">
|
||||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.3.1...1.3.3">1.3.3</a>
|
<a href="https://github.com/jashkenas/coffee-script/compare/1.3.1...1.3.3">1.3.3</a>
|
||||||
|
|
@ -1146,7 +1147,7 @@ Expressions
|
||||||
<li>
|
<li>
|
||||||
Due to the new semantics of JavaScript's strict mode, CoffeeScript no
|
Due to the new semantics of JavaScript's strict mode, CoffeeScript no
|
||||||
longer guarantees that constructor functions have names in all runtimes.
|
longer guarantees that constructor functions have names in all runtimes.
|
||||||
See <a href="https://github.com/jashkenas/coffee-script/issues/2052">#2052</a>
|
See <a href="https://github.com/jashkenas/coffee-script/issues/2052">#2052</a>
|
||||||
for discussion.
|
for discussion.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -1165,7 +1166,7 @@ Expressions
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b class="header" style="margin-top: 20px;">
|
<b class="header" style="margin-top: 20px;">
|
||||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.2.0...1.3.1">1.3.1</a>
|
<a href="https://github.com/jashkenas/coffee-script/compare/1.2.0...1.3.1">1.3.1</a>
|
||||||
|
|
@ -1173,26 +1174,26 @@ Expressions
|
||||||
</b>
|
</b>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
CoffeeScript now enforces all of JavaScript's <b>Strict Mode</b> early syntax
|
CoffeeScript now enforces all of JavaScript's <b>Strict Mode</b> early syntax
|
||||||
errors at compile time. This includes old-style octal literals,
|
errors at compile time. This includes old-style octal literals,
|
||||||
duplicate property names in object literals, duplicate parameters in
|
duplicate property names in object literals, duplicate parameters in
|
||||||
a function definition, deleting naked variables, setting the value of
|
a function definition, deleting naked variables, setting the value of
|
||||||
<tt>eval</tt> or <tt>arguments</tt>, and more.
|
<tt>eval</tt> or <tt>arguments</tt>, and more.
|
||||||
See a full discussion at
|
See a full discussion at
|
||||||
<a href="https://github.com/jashkenas/coffee-script/issues/1547">#1547</a>.
|
<a href="https://github.com/jashkenas/coffee-script/issues/1547">#1547</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
The REPL now has a handy new multi-line mode for entering large
|
The REPL now has a handy new multi-line mode for entering large
|
||||||
blocks of code. It's useful when copy-and-pasting examples into the
|
blocks of code. It's useful when copy-and-pasting examples into the
|
||||||
REPL. Enter multi-line mode with <tt>Ctrl-V</tt>. You may also now
|
REPL. Enter multi-line mode with <tt>Ctrl-V</tt>. You may also now
|
||||||
pipe input directly into the REPL.
|
pipe input directly into the REPL.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
CoffeeScript now prints a <tt>Generated by CoffeeScript VERSION</tt>
|
CoffeeScript now prints a <tt>Generated by CoffeeScript VERSION</tt>
|
||||||
header at the top of each compiled file.
|
header at the top of each compiled file.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Conditional assignment of previously undefined variables
|
Conditional assignment of previously undefined variables
|
||||||
<tt>a or= b</tt> is now considered a syntax error.
|
<tt>a or= b</tt> is now considered a syntax error.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -1204,18 +1205,18 @@ Expressions
|
||||||
between them.
|
between them.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Both endpoints of a slice are now allowed to be omitted for consistency,
|
Both endpoints of a slice are now allowed to be omitted for consistency,
|
||||||
effectively creating a shallow copy of the list.
|
effectively creating a shallow copy of the list.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Additional tweaks and improvments to <tt>coffee --watch</tt> under
|
Additional tweaks and improvments to <tt>coffee --watch</tt> under
|
||||||
Node's "new" file watching API. Watch will now beep by default
|
Node's "new" file watching API. Watch will now beep by default
|
||||||
if you introduce a syntax error into a watched script. We also now
|
if you introduce a syntax error into a watched script. We also now
|
||||||
ignore hidden directories by default when watching recursively.
|
ignore hidden directories by default when watching recursively.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b class="header" style="margin-top: 20px;">
|
<b class="header" style="margin-top: 20px;">
|
||||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.3...1.2.0">1.2.0</a>
|
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.3...1.2.0">1.2.0</a>
|
||||||
|
|
@ -1242,7 +1243,7 @@ Expressions
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b class="header" style="margin-top: 20px;">
|
<b class="header" style="margin-top: 20px;">
|
||||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.2...1.1.3">1.1.3</a>
|
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.2...1.1.3">1.1.3</a>
|
||||||
|
|
@ -1254,7 +1255,7 @@ Expressions
|
||||||
out and keep it readable, as you can see in the examples on this page.
|
out and keep it readable, as you can see in the examples on this page.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
You can now call <tt>super</tt> in class level methods in class bodies,
|
You can now call <tt>super</tt> in class level methods in class bodies,
|
||||||
and bound class methods now preserve their correct context.
|
and bound class methods now preserve their correct context.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -1263,7 +1264,7 @@ Expressions
|
||||||
also supports binary numbers: <tt>0b10 is 2</tt>.
|
also supports binary numbers: <tt>0b10 is 2</tt>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
The CoffeeScript module has been nested under a subdirectory to make
|
The CoffeeScript module has been nested under a subdirectory to make
|
||||||
it easier to <tt>require</tt> individual components separately, without
|
it easier to <tt>require</tt> individual components separately, without
|
||||||
having to use <b>npm</b>. For example, after adding the CoffeeScript
|
having to use <b>npm</b>. For example, after adding the CoffeeScript
|
||||||
folder to your path: <tt>require('coffee-script/lexer')</tt>
|
folder to your path: <tt>require('coffee-script/lexer')</tt>
|
||||||
|
|
@ -1273,11 +1274,11 @@ Expressions
|
||||||
it to get a shareable permalink for your example script.
|
it to get a shareable permalink for your example script.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
The <tt>coffee --watch</tt> feature now only works on Node.js 0.6.0
|
The <tt>coffee --watch</tt> feature now only works on Node.js 0.6.0
|
||||||
and higher, but now also works properly on Windows.
|
and higher, but now also works properly on Windows.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Lots of small bug fixes from
|
Lots of small bug fixes from
|
||||||
<b><a href="https://github.com/michaelficarra">@michaelficarra</a></b>,
|
<b><a href="https://github.com/michaelficarra">@michaelficarra</a></b>,
|
||||||
<b><a href="https://github.com/geraldalewis">@geraldalewis</a></b>,
|
<b><a href="https://github.com/geraldalewis">@geraldalewis</a></b>,
|
||||||
<b><a href="https://github.com/satyr">@satyr</a></b>, and
|
<b><a href="https://github.com/satyr">@satyr</a></b>, and
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var CoffeeScript, runScripts;
|
var CoffeeScript, runScripts;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var CoffeeScript, cakefileDirectory, existsSync, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
var CoffeeScript, cakefileDirectory, existsSync, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,38 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, stripBOM, vm, _ref,
|
var Lexer, compile, ext, extensions, fs, lexer, loadFile, parser, path, vm, _i, _len,
|
||||||
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||||
__hasProp = {}.hasOwnProperty;
|
__hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
path = require('path');
|
path = require('path');
|
||||||
|
|
||||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
Lexer = require('./lexer').Lexer;
|
||||||
|
|
||||||
parser = require('./parser').parser;
|
parser = require('./parser').parser;
|
||||||
|
|
||||||
vm = require('vm');
|
vm = require('vm');
|
||||||
|
|
||||||
stripBOM = function(content) {
|
extensions = ['.coffee', '.litcoffee'];
|
||||||
if (content.charCodeAt(0) === 0xFEFF) {
|
|
||||||
return content.substring(1);
|
loadFile = function(module, filename) {
|
||||||
} else {
|
var raw, stripped;
|
||||||
return content;
|
raw = fs.readFileSync(filename, 'utf8');
|
||||||
}
|
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||||
|
return module._compile(compile(stripped, {
|
||||||
|
filename: filename
|
||||||
|
}), filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (require.extensions) {
|
if (require.extensions) {
|
||||||
require.extensions['.coffee'] = function(module, filename) {
|
for (_i = 0, _len = extensions.length; _i < _len; _i++) {
|
||||||
var content;
|
ext = extensions[_i];
|
||||||
content = compile(stripBOM(fs.readFileSync(filename, 'utf8')), {
|
require.extensions[ext] = loadFile;
|
||||||
filename: filename
|
}
|
||||||
});
|
|
||||||
return module._compile(content, filename);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.VERSION = '1.4.0';
|
exports.VERSION = '1.5.0-pre';
|
||||||
|
|
||||||
exports.RESERVED = RESERVED;
|
|
||||||
|
|
||||||
exports.helpers = require('./helpers');
|
exports.helpers = require('./helpers');
|
||||||
|
|
||||||
|
|
@ -44,7 +43,7 @@
|
||||||
}
|
}
|
||||||
merge = exports.helpers.merge;
|
merge = exports.helpers.merge;
|
||||||
try {
|
try {
|
||||||
js = (parser.parse(lexer.tokenize(code))).compile(options);
|
js = (parser.parse(lexer.tokenize(code, options))).compile(options);
|
||||||
if (!options.header) {
|
if (!options.header) {
|
||||||
return js;
|
return js;
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +70,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.run = function(code, options) {
|
exports.run = function(code, options) {
|
||||||
var mainModule;
|
var mainModule, _ref;
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +78,7 @@
|
||||||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||||
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
|
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
|
||||||
if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) {
|
if ((_ref = path.extname(mainModule.filename), __indexOf.call(extensions, _ref) < 0) || require.extensions) {
|
||||||
return mainModule._compile(compile(code, options), mainModule.filename);
|
return mainModule._compile(compile(code, options), mainModule.filename);
|
||||||
} else {
|
} else {
|
||||||
return mainModule._compile(code, mainModule.filename);
|
return mainModule._compile(code, mainModule.filename);
|
||||||
|
|
@ -87,7 +86,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["eval"] = function(code, options) {
|
exports["eval"] = function(code, options) {
|
||||||
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref1, _ref2, _require;
|
var Module, Script, js, k, o, r, sandbox, v, _j, _len1, _module, _ref, _ref1, _require;
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
@ -101,10 +100,10 @@
|
||||||
sandbox = options.sandbox;
|
sandbox = options.sandbox;
|
||||||
} else {
|
} else {
|
||||||
sandbox = Script.createContext();
|
sandbox = Script.createContext();
|
||||||
_ref1 = options.sandbox;
|
_ref = options.sandbox;
|
||||||
for (k in _ref1) {
|
for (k in _ref) {
|
||||||
if (!__hasProp.call(_ref1, k)) continue;
|
if (!__hasProp.call(_ref, k)) continue;
|
||||||
v = _ref1[k];
|
v = _ref[k];
|
||||||
sandbox[k] = v;
|
sandbox[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,9 +120,9 @@
|
||||||
return Module._load(path, _module, true);
|
return Module._load(path, _module, true);
|
||||||
};
|
};
|
||||||
_module.filename = sandbox.__filename;
|
_module.filename = sandbox.__filename;
|
||||||
_ref2 = Object.getOwnPropertyNames(require);
|
_ref1 = Object.getOwnPropertyNames(require);
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||||
r = _ref2[_i];
|
r = _ref1[_j];
|
||||||
if (r !== 'paths') {
|
if (r !== 'paths') {
|
||||||
_require[r] = require[r];
|
_require[r] = require[r];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, loadRequires, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref;
|
var BANNER, CoffeeScript, EventEmitter, SWITCHES, coffee_exts, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, loadRequires, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref,
|
||||||
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
|
|
@ -48,6 +49,8 @@
|
||||||
|
|
||||||
optionParser = null;
|
optionParser = null;
|
||||||
|
|
||||||
|
coffee_exts = ['.coffee', '.litcoffee'];
|
||||||
|
|
||||||
exports.run = function() {
|
exports.run = function() {
|
||||||
var literals, source, _i, _len, _results;
|
var literals, source, _i, _len, _results;
|
||||||
parseOptions();
|
parseOptions();
|
||||||
|
|
@ -92,11 +95,12 @@
|
||||||
|
|
||||||
compilePath = function(source, topLevel, base) {
|
compilePath = function(source, topLevel, base) {
|
||||||
return fs.stat(source, function(err, stats) {
|
return fs.stat(source, function(err, stats) {
|
||||||
|
var _ref1, _ref2;
|
||||||
if (err && err.code !== 'ENOENT') {
|
if (err && err.code !== 'ENOENT') {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
if ((err != null ? err.code : void 0) === 'ENOENT') {
|
if ((err != null ? err.code : void 0) === 'ENOENT') {
|
||||||
if (topLevel && source.slice(-7) !== '.coffee') {
|
if (topLevel && (_ref1 = path.extname(source), __indexOf.call(coffee_exts, _ref1) < 0)) {
|
||||||
source = sources[sources.indexOf(source)] = "" + source + ".coffee";
|
source = sources[sources.indexOf(source)] = "" + source + ".coffee";
|
||||||
return compilePath(source, topLevel, base);
|
return compilePath(source, topLevel, base);
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +115,7 @@
|
||||||
watchDir(source, base);
|
watchDir(source, base);
|
||||||
}
|
}
|
||||||
return fs.readdir(source, function(err, files) {
|
return fs.readdir(source, function(err, files) {
|
||||||
var file, index, _ref1, _ref2;
|
var file, index, _ref2, _ref3;
|
||||||
if (err && err.code !== 'ENOENT') {
|
if (err && err.code !== 'ENOENT') {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +126,7 @@
|
||||||
files = files.filter(function(file) {
|
files = files.filter(function(file) {
|
||||||
return !hidden(file);
|
return !hidden(file);
|
||||||
});
|
});
|
||||||
[].splice.apply(sources, [index, index - index + 1].concat(_ref1 = (function() {
|
[].splice.apply(sources, [index, index - index + 1].concat(_ref2 = (function() {
|
||||||
var _i, _len, _results;
|
var _i, _len, _results;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||||
|
|
@ -130,15 +134,15 @@
|
||||||
_results.push(path.join(source, file));
|
_results.push(path.join(source, file));
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
})())), _ref1;
|
})())), _ref2;
|
||||||
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() {
|
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref3 = files.map(function() {
|
||||||
return null;
|
return null;
|
||||||
}))), _ref2;
|
}))), _ref3;
|
||||||
return files.forEach(function(file) {
|
return files.forEach(function(file) {
|
||||||
return compilePath(path.join(source, file), false, base);
|
return compilePath(path.join(source, file), false, base);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
} else if (topLevel || (_ref2 = path.extname(source), __indexOf.call(coffee_exts, _ref2) >= 0)) {
|
||||||
if (opts.watch) {
|
if (opts.watch) {
|
||||||
watch(source, base);
|
watch(source, base);
|
||||||
}
|
}
|
||||||
|
|
@ -170,9 +174,9 @@
|
||||||
};
|
};
|
||||||
CoffeeScript.emit('compile', task);
|
CoffeeScript.emit('compile', task);
|
||||||
if (o.tokens) {
|
if (o.tokens) {
|
||||||
return printTokens(CoffeeScript.tokens(t.input));
|
return printTokens(CoffeeScript.tokens(t.input, t.options));
|
||||||
} else if (o.nodes) {
|
} else if (o.nodes) {
|
||||||
return printLine(CoffeeScript.nodes(t.input).toString().trim());
|
return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim());
|
||||||
} else if (o.run) {
|
} else if (o.run) {
|
||||||
return CoffeeScript.run(t.input, t.options);
|
return CoffeeScript.run(t.input, t.options);
|
||||||
} else if (o.join && t.file !== o.join) {
|
} else if (o.join && t.file !== o.join) {
|
||||||
|
|
@ -472,8 +476,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
compileOptions = function(filename) {
|
compileOptions = function(filename) {
|
||||||
|
var literate;
|
||||||
|
literate = path.extname(filename) === '.litcoffee';
|
||||||
return {
|
return {
|
||||||
filename: filename,
|
filename: filename,
|
||||||
|
literate: literate,
|
||||||
bare: opts.bare,
|
bare: opts.bare,
|
||||||
header: opts.compile
|
header: opts.compile
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
||||||
|
|
||||||
|
|
@ -575,6 +575,9 @@
|
||||||
}), o('SimpleAssignable COMPOUND_ASSIGN\
|
}), o('SimpleAssignable COMPOUND_ASSIGN\
|
||||||
INDENT Expression OUTDENT', function() {
|
INDENT Expression OUTDENT', function() {
|
||||||
return new Assign($1, $4, $2);
|
return new Assign($1, $4, $2);
|
||||||
|
}), o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR\
|
||||||
|
Expression', function() {
|
||||||
|
return new Assign($1, $4, $2);
|
||||||
}), o('SimpleAssignable EXTENDS Expression', function() {
|
}), o('SimpleAssignable EXTENDS Expression', function() {
|
||||||
return new Extends($1, $3);
|
return new Extends($1, $3);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var buildLocationData, extend, flatten, _ref;
|
var buildLocationData, extend, flatten, _ref;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var key, val, _ref;
|
var key, val, _ref;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, locationDataToString, starts, _ref, _ref1,
|
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LITERATE, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, locationDataToString, starts, _ref, _ref1,
|
||||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
|
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
|
||||||
|
|
@ -16,19 +16,16 @@
|
||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
if (WHITESPACE.test(code)) {
|
this.literate = opts.literate;
|
||||||
code = "\n" + code;
|
code = this.clean(code);
|
||||||
}
|
|
||||||
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
|
||||||
this.code = code;
|
|
||||||
this.chunkLine = opts.line || 0;
|
|
||||||
this.chunkColumn = opts.column || 0;
|
|
||||||
this.indent = 0;
|
this.indent = 0;
|
||||||
this.indebt = 0;
|
this.indebt = 0;
|
||||||
this.outdebt = 0;
|
this.outdebt = 0;
|
||||||
this.indents = [];
|
this.indents = [];
|
||||||
this.ends = [];
|
this.ends = [];
|
||||||
this.tokens = [];
|
this.tokens = [];
|
||||||
|
this.chunkLine = opts.line || 0;
|
||||||
|
this.chunkColumn = opts.column || 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (this.chunk = code.slice(i)) {
|
while (this.chunk = code.slice(i)) {
|
||||||
consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
|
consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
|
||||||
|
|
@ -45,6 +42,35 @@
|
||||||
return (new Rewriter).rewrite(this.tokens);
|
return (new Rewriter).rewrite(this.tokens);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Lexer.prototype.clean = function(code) {
|
||||||
|
var line, lines, match;
|
||||||
|
if (code.charCodeAt(0) === BOM) {
|
||||||
|
code = code.slice(1);
|
||||||
|
}
|
||||||
|
if (WHITESPACE.test(code)) {
|
||||||
|
code = "\n" + code;
|
||||||
|
}
|
||||||
|
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
||||||
|
if (this.literate) {
|
||||||
|
lines = (function() {
|
||||||
|
var _i, _len, _ref2, _results;
|
||||||
|
_ref2 = code.split('\n');
|
||||||
|
_results = [];
|
||||||
|
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||||
|
line = _ref2[_i];
|
||||||
|
if (match = LITERATE.exec(line)) {
|
||||||
|
_results.push(line.slice(match[0].length));
|
||||||
|
} else {
|
||||||
|
_results.push('# ' + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
})();
|
||||||
|
code = lines.join('\n');
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
Lexer.prototype.identifierToken = function() {
|
Lexer.prototype.identifierToken = function() {
|
||||||
var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4;
|
var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4;
|
||||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||||
|
|
@ -486,7 +512,7 @@
|
||||||
if (HEREDOC_ILLEGAL.test(doc)) {
|
if (HEREDOC_ILLEGAL.test(doc)) {
|
||||||
this.error("block comment cannot contain \"*/\", starting");
|
this.error("block comment cannot contain \"*/\", starting");
|
||||||
}
|
}
|
||||||
if (doc.indexOf('\n') <= 0) {
|
if (doc.indexOf('\n') < 0) {
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -804,6 +830,8 @@
|
||||||
|
|
||||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
|
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
|
||||||
|
|
||||||
|
BOM = 65279;
|
||||||
|
|
||||||
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
|
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
|
||||||
|
|
||||||
NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
|
NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
|
||||||
|
|
@ -814,7 +842,9 @@
|
||||||
|
|
||||||
WHITESPACE = /^[^\n\S]+/;
|
WHITESPACE = /^[^\n\S]+/;
|
||||||
|
|
||||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||||
|
|
||||||
|
LITERATE = /^([ ]{4}|\t)/;
|
||||||
|
|
||||||
CODE = /^[-=]>/;
|
CODE = /^[-=]>/;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, last, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1,
|
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, last, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1,
|
||||||
__hasProp = {}.hasOwnProperty,
|
__hasProp = {}.hasOwnProperty,
|
||||||
|
|
@ -1937,7 +1937,7 @@
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||||
obj = _ref2[_i];
|
obj = _ref2[_i];
|
||||||
if (obj instanceof Assign) {
|
if (obj instanceof Assign) {
|
||||||
names.push(obj.value.unwrap().value);
|
names.push.apply(names, this.names(obj.value.unwrap()));
|
||||||
} else if (obj instanceof Splat) {
|
} else if (obj instanceof Splat) {
|
||||||
names.push(obj.name.unwrap().value);
|
names.push(obj.name.unwrap().value);
|
||||||
} else if (obj instanceof Value) {
|
} else if (obj instanceof Value) {
|
||||||
|
|
@ -2904,6 +2904,9 @@
|
||||||
func = new Code([], Block.wrap([expressions]));
|
func = new Code([], Block.wrap([expressions]));
|
||||||
args = [];
|
args = [];
|
||||||
if ((mentionsArgs = expressions.contains(this.literalArgs)) || expressions.contains(this.literalThis)) {
|
if ((mentionsArgs = expressions.contains(this.literalArgs)) || expressions.contains(this.literalThis)) {
|
||||||
|
if (mentionsArgs && expressions.classBody) {
|
||||||
|
throw SyntaxError("Class bodies shouldn't reference arguments");
|
||||||
|
}
|
||||||
meth = new Literal(mentionsArgs ? 'apply' : 'call');
|
meth = new Literal(mentionsArgs ? 'apply' : 'call');
|
||||||
args = [new Literal('this')];
|
args = [new Literal('this')];
|
||||||
if (mentionsArgs) {
|
if (mentionsArgs) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, REPL_PROMPT_MULTILINE, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, multilineMode, pipedInput, readline, repl, run, stdin, stdout,
|
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, REPL_PROMPT_MULTILINE, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, multilineMode, pipedInput, readline, repl, run, stdin, stdout,
|
||||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref,
|
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref,
|
||||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var Scope, extend, last, _ref;
|
var Scope, extend, last, _ref;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.4.0
|
// Generated by CoffeeScript 1.5.0-pre
|
||||||
(function() {
|
(function() {
|
||||||
var BASE64_CHARS, LineMapping, MAX_BASE64_VALUE, VLQ_CONTINUATION_BIT, VLQ_MASK, VLQ_SHIFT, encodeBase64Char;
|
var BASE64_CHARS, LineMapping, MAX_BASE64_VALUE, VLQ_CONTINUATION_BIT, VLQ_MASK, VLQ_SHIFT, encodeBase64Char;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"description": "Unfancy JavaScript",
|
"description": "Unfancy JavaScript",
|
||||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||||
"author": "Jeremy Ashkenas",
|
"author": "Jeremy Ashkenas",
|
||||||
"version": "1.4.0",
|
"version": "1.5.0-pre",
|
||||||
"licenses": [{
|
"licenses": [{
|
||||||
"type": "MIT",
|
"type": "MIT",
|
||||||
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
|
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"url": "git://github.com/jashkenas/coffee-script.git"
|
"url": "git://github.com/jashkenas/coffee-script.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"uglify-js": ">=1.0.0",
|
"uglify-js": "~2.2",
|
||||||
"jison": ">=0.2.0"
|
"jison": ">=0.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,25 +6,27 @@
|
||||||
# If included on a webpage, it will automatically sniff out, compile, and
|
# If included on a webpage, it will automatically sniff out, compile, and
|
||||||
# execute all scripts present in `text/coffeescript` tags.
|
# execute all scripts present in `text/coffeescript` tags.
|
||||||
|
|
||||||
fs = require 'fs'
|
fs = require 'fs'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
{Lexer,RESERVED} = require './lexer'
|
{Lexer} = require './lexer'
|
||||||
{parser} = require './parser'
|
{parser} = require './parser'
|
||||||
vm = require 'vm'
|
vm = require 'vm'
|
||||||
|
|
||||||
stripBOM = (content) ->
|
# The file extensions that are considered to be CoffeeScript.
|
||||||
if content.charCodeAt(0) is 0xFEFF then content.substring 1 else content
|
extensions = ['.coffee', '.litcoffee']
|
||||||
|
|
||||||
|
# Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||||
|
loadFile = (module, filename) ->
|
||||||
|
raw = fs.readFileSync filename, 'utf8'
|
||||||
|
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||||
|
module._compile compile(stripped, {filename}), filename
|
||||||
|
|
||||||
if require.extensions
|
if require.extensions
|
||||||
require.extensions['.coffee'] = (module, filename) ->
|
for ext in extensions
|
||||||
content = compile stripBOM(fs.readFileSync filename, 'utf8'), {filename}
|
require.extensions[ext] = loadFile
|
||||||
module._compile content, filename
|
|
||||||
|
|
||||||
# The current CoffeeScript version number.
|
# The current CoffeeScript version number.
|
||||||
exports.VERSION = '1.4.0'
|
exports.VERSION = '1.5.0-pre'
|
||||||
|
|
||||||
# Words that cannot be used as identifiers in CoffeeScript code
|
|
||||||
exports.RESERVED = RESERVED
|
|
||||||
|
|
||||||
# Expose helpers for testing.
|
# Expose helpers for testing.
|
||||||
exports.helpers = require './helpers'
|
exports.helpers = require './helpers'
|
||||||
|
|
@ -34,7 +36,7 @@ exports.helpers = require './helpers'
|
||||||
exports.compile = compile = (code, options = {}) ->
|
exports.compile = compile = (code, options = {}) ->
|
||||||
{merge} = exports.helpers
|
{merge} = exports.helpers
|
||||||
try
|
try
|
||||||
js = (parser.parse lexer.tokenize code).compile options
|
js = (parser.parse lexer.tokenize(code, options)).compile options
|
||||||
return js unless options.header
|
return js unless options.header
|
||||||
catch err
|
catch err
|
||||||
err.message = "In #{options.filename}, #{err.message}" if options.filename
|
err.message = "In #{options.filename}, #{err.message}" if options.filename
|
||||||
|
|
@ -71,7 +73,7 @@ exports.run = (code, options = {}) ->
|
||||||
mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename
|
mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename
|
||||||
|
|
||||||
# Compile.
|
# Compile.
|
||||||
if path.extname(mainModule.filename) isnt '.coffee' or require.extensions
|
if (path.extname(mainModule.filename) not in extensions) or require.extensions
|
||||||
mainModule._compile compile(code, options), mainModule.filename
|
mainModule._compile compile(code, options), mainModule.filename
|
||||||
else
|
else
|
||||||
mainModule._compile code, mainModule.filename
|
mainModule._compile code, mainModule.filename
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ sourceCode = []
|
||||||
notSources = {}
|
notSources = {}
|
||||||
watchers = {}
|
watchers = {}
|
||||||
optionParser = null
|
optionParser = null
|
||||||
|
coffee_exts = ['.coffee', '.litcoffee']
|
||||||
|
|
||||||
# Run `coffee` by parsing passed options and determining what action to take.
|
# Run `coffee` by parsing passed options and determining what action to take.
|
||||||
# Many flags cause us to divert before compiling anything. Flags passed after
|
# Many flags cause us to divert before compiling anything. Flags passed after
|
||||||
|
|
@ -81,13 +82,13 @@ exports.run = ->
|
||||||
compilePath source, yes, path.normalize source
|
compilePath source, yes, path.normalize source
|
||||||
|
|
||||||
# Compile a path, which could be a script or a directory. If a directory
|
# Compile a path, which could be a script or a directory. If a directory
|
||||||
# is passed, recursively compile all '.coffee' extension source files in it
|
# is passed, recursively compile all '.coffee' and '.litcoffee' extension source
|
||||||
# and all subdirectories.
|
# files in it and all subdirectories.
|
||||||
compilePath = (source, topLevel, base) ->
|
compilePath = (source, topLevel, base) ->
|
||||||
fs.stat source, (err, stats) ->
|
fs.stat source, (err, stats) ->
|
||||||
throw err if err and err.code isnt 'ENOENT'
|
throw err if err and err.code isnt 'ENOENT'
|
||||||
if err?.code is 'ENOENT'
|
if err?.code is 'ENOENT'
|
||||||
if topLevel and source[-7..] isnt '.coffee'
|
if topLevel and path.extname(source) not in coffee_exts
|
||||||
source = sources[sources.indexOf(source)] = "#{source}.coffee"
|
source = sources[sources.indexOf(source)] = "#{source}.coffee"
|
||||||
return compilePath source, topLevel, base
|
return compilePath source, topLevel, base
|
||||||
if topLevel
|
if topLevel
|
||||||
|
|
@ -105,7 +106,7 @@ compilePath = (source, topLevel, base) ->
|
||||||
sourceCode[index..index] = files.map -> null
|
sourceCode[index..index] = files.map -> null
|
||||||
files.forEach (file) ->
|
files.forEach (file) ->
|
||||||
compilePath (path.join source, file), no, base
|
compilePath (path.join source, file), no, base
|
||||||
else if topLevel or path.extname(source) is '.coffee'
|
else if topLevel or path.extname(source) in coffee_exts
|
||||||
watch source, base if opts.watch
|
watch source, base if opts.watch
|
||||||
fs.readFile source, (err, code) ->
|
fs.readFile source, (err, code) ->
|
||||||
throw err if err and err.code isnt 'ENOENT'
|
throw err if err and err.code isnt 'ENOENT'
|
||||||
|
|
@ -125,8 +126,8 @@ compileScript = (file, input, base) ->
|
||||||
try
|
try
|
||||||
t = task = {file, input, options}
|
t = task = {file, input, options}
|
||||||
CoffeeScript.emit 'compile', task
|
CoffeeScript.emit 'compile', task
|
||||||
if o.tokens then printTokens CoffeeScript.tokens t.input
|
if o.tokens then printTokens CoffeeScript.tokens t.input, t.options
|
||||||
else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim()
|
else if o.nodes then printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
|
||||||
else if o.run then CoffeeScript.run t.input, t.options
|
else if o.run then CoffeeScript.run t.input, t.options
|
||||||
else if o.join and t.file isnt o.join
|
else if o.join and t.file isnt o.join
|
||||||
sourceCode[sources.indexOf(t.file)] = t.input
|
sourceCode[sources.indexOf(t.file)] = t.input
|
||||||
|
|
@ -318,7 +319,8 @@ parseOptions = ->
|
||||||
|
|
||||||
# The compile-time options to pass to the CoffeeScript compiler.
|
# The compile-time options to pass to the CoffeeScript compiler.
|
||||||
compileOptions = (filename) ->
|
compileOptions = (filename) ->
|
||||||
{filename, bare: opts.bare, header: opts.compile}
|
literate = path.extname(filename) is '.litcoffee'
|
||||||
|
{filename, literate, bare: opts.bare, header: opts.compile}
|
||||||
|
|
||||||
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
||||||
# the `node` binary, preserving the other options.
|
# the `node` binary, preserving the other options.
|
||||||
|
|
|
||||||
|
|
@ -558,6 +558,8 @@ grammar =
|
||||||
Expression', -> new Assign $1, $3, $2
|
Expression', -> new Assign $1, $3, $2
|
||||||
o 'SimpleAssignable COMPOUND_ASSIGN
|
o 'SimpleAssignable COMPOUND_ASSIGN
|
||||||
INDENT Expression OUTDENT', -> new Assign $1, $4, $2
|
INDENT Expression OUTDENT', -> new Assign $1, $4, $2
|
||||||
|
o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR
|
||||||
|
Expression', -> new Assign $1, $4, $2
|
||||||
o 'SimpleAssignable EXTENDS Expression', -> new Extends $1, $3
|
o 'SimpleAssignable EXTENDS Expression', -> new Extends $1, $3
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,20 +32,19 @@ exports.Lexer = class Lexer
|
||||||
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||||
# unless explicitly asked not to.
|
# unless explicitly asked not to.
|
||||||
tokenize: (code, opts = {}) ->
|
tokenize: (code, opts = {}) ->
|
||||||
code = "\n#{code}" if WHITESPACE.test code
|
@literate = opts.literate # Are we lexing literate CoffeeScript?
|
||||||
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
code = @clean code # The stripped, cleaned original source code.
|
||||||
|
@indent = 0 # The current indentation level.
|
||||||
|
@indebt = 0 # The over-indentation at the current level.
|
||||||
|
@outdebt = 0 # The under-outdentation at the current level.
|
||||||
|
@indents = [] # The stack of all current indentation levels.
|
||||||
|
@ends = [] # The stack for pairing up tokens.
|
||||||
|
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`.
|
||||||
|
|
||||||
@code = code # The source code.
|
|
||||||
@chunkLine =
|
@chunkLine =
|
||||||
opts.line or 0 # The start line for the current chunk.
|
opts.line or 0 # The start line for the current @chunk.
|
||||||
@chunkColumn =
|
@chunkColumn =
|
||||||
opts.column or 0 # The start column of the current chunk.
|
opts.column or 0 # The start column of the current @chunk.
|
||||||
@indent = 0 # The current indentation level.
|
|
||||||
@indebt = 0 # The over-indentation at the current level.
|
|
||||||
@outdebt = 0 # The under-outdentation at the current level.
|
|
||||||
@indents = [] # The stack of all current indentation levels.
|
|
||||||
@ends = [] # The stack for pairing up tokens.
|
|
||||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`.
|
|
||||||
|
|
||||||
# At every position, run through this list of attempted matches,
|
# At every position, run through this list of attempted matches,
|
||||||
# short-circuiting if any of them succeed. Their order determines precedence:
|
# short-circuiting if any of them succeed. Their order determines precedence:
|
||||||
|
|
@ -74,6 +73,22 @@ exports.Lexer = class Lexer
|
||||||
return @tokens if opts.rewrite is off
|
return @tokens if opts.rewrite is off
|
||||||
(new Rewriter).rewrite @tokens
|
(new Rewriter).rewrite @tokens
|
||||||
|
|
||||||
|
# Preprocess the code to remove leading and trailing whitespace, carriage
|
||||||
|
# returns, etc. If we're lexing literate CoffeeScript, strip external Markdown
|
||||||
|
# by removing all lines that aren't indented by at least four spaces or a tab.
|
||||||
|
clean: (code) ->
|
||||||
|
code = code.slice(1) if code.charCodeAt(0) is BOM
|
||||||
|
code = "\n#{code}" if WHITESPACE.test code
|
||||||
|
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
||||||
|
if @literate
|
||||||
|
lines = for line in code.split('\n')
|
||||||
|
if match = LITERATE.exec line
|
||||||
|
line[match[0].length..]
|
||||||
|
else
|
||||||
|
'# ' + line
|
||||||
|
code = lines.join '\n'
|
||||||
|
code
|
||||||
|
|
||||||
# Tokenizers
|
# Tokenizers
|
||||||
# ----------
|
# ----------
|
||||||
|
|
||||||
|
|
@ -87,6 +102,7 @@ exports.Lexer = class Lexer
|
||||||
return 0 unless match = IDENTIFIER.exec @chunk
|
return 0 unless match = IDENTIFIER.exec @chunk
|
||||||
[input, id, colon] = match
|
[input, id, colon] = match
|
||||||
|
|
||||||
|
# Preserve lenght of id for location data
|
||||||
idLength = id.length
|
idLength = id.length
|
||||||
poppedToken = undefined
|
poppedToken = undefined
|
||||||
|
|
||||||
|
|
@ -417,7 +433,7 @@ exports.Lexer = class Lexer
|
||||||
if herecomment
|
if herecomment
|
||||||
if HEREDOC_ILLEGAL.test doc
|
if HEREDOC_ILLEGAL.test doc
|
||||||
@error "block comment cannot contain \"*/\", starting"
|
@error "block comment cannot contain \"*/\", starting"
|
||||||
return doc if doc.indexOf('\n') <= 0
|
return doc if doc.indexOf('\n') < 0
|
||||||
else
|
else
|
||||||
while match = HEREDOC_INDENT.exec doc
|
while match = HEREDOC_INDENT.exec doc
|
||||||
attempt = match[1]
|
attempt = match[1]
|
||||||
|
|
@ -596,6 +612,8 @@ exports.Lexer = class Lexer
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
# Returns the line and column number from an offset into the current chunk.
|
# Returns the line and column number from an offset into the current chunk.
|
||||||
|
#
|
||||||
|
# `offset` is a number of characters into @chunk.
|
||||||
getLineAndColumnFromChunk: (offset) ->
|
getLineAndColumnFromChunk: (offset) ->
|
||||||
if offset is 0
|
if offset is 0
|
||||||
return [@chunkLine, @chunkColumn]
|
return [@chunkLine, @chunkColumn]
|
||||||
|
|
@ -724,6 +742,9 @@ JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
|
||||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
|
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
|
||||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED
|
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED
|
||||||
|
|
||||||
|
# The character code of the nasty Microsoft madness otherwise known as the BOM.
|
||||||
|
BOM = 65279
|
||||||
|
|
||||||
# Token matching regexes.
|
# Token matching regexes.
|
||||||
IDENTIFIER = /// ^
|
IDENTIFIER = /// ^
|
||||||
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
|
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
|
||||||
|
|
@ -751,7 +772,9 @@ OPERATOR = /// ^ (
|
||||||
|
|
||||||
WHITESPACE = /^[^\n\S]+/
|
WHITESPACE = /^[^\n\S]+/
|
||||||
|
|
||||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/
|
||||||
|
|
||||||
|
LITERATE = /^([ ]{4}|\t)/
|
||||||
|
|
||||||
CODE = /^[-=]>/
|
CODE = /^[-=]>/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1307,7 +1307,7 @@ exports.Param = class Param extends Base
|
||||||
for obj in name.objects
|
for obj in name.objects
|
||||||
# * assignments within destructured parameters `{foo:bar}`
|
# * assignments within destructured parameters `{foo:bar}`
|
||||||
if obj instanceof Assign
|
if obj instanceof Assign
|
||||||
names.push obj.value.unwrap().value
|
names.push @names(obj.value.unwrap())...
|
||||||
# * splats within destructured parameters `[xs...]`
|
# * splats within destructured parameters `[xs...]`
|
||||||
else if obj instanceof Splat
|
else if obj instanceof Splat
|
||||||
names.push obj.name.unwrap().value
|
names.push obj.name.unwrap().value
|
||||||
|
|
@ -1952,6 +1952,8 @@ Closure =
|
||||||
func = new Code [], Block.wrap [expressions]
|
func = new Code [], Block.wrap [expressions]
|
||||||
args = []
|
args = []
|
||||||
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
||||||
|
if mentionsArgs and expressions.classBody
|
||||||
|
throw SyntaxError "Class bodies shouldn't reference arguments"
|
||||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||||
args = [new Literal 'this']
|
args = [new Literal 'this']
|
||||||
args.push new Literal 'arguments' if mentionsArgs
|
args.push new Literal 'arguments' if mentionsArgs
|
||||||
|
|
|
||||||
101
src/scope.coffee
101
src/scope.coffee
|
|
@ -1,101 +0,0 @@
|
||||||
# The **Scope** class regulates lexical scoping within CoffeeScript. As you
|
|
||||||
# generate code, you create a tree of scopes in the same shape as the nested
|
|
||||||
# function bodies. Each scope knows about the variables declared within it,
|
|
||||||
# and has a reference to its parent enclosing scope. In this way, we know which
|
|
||||||
# variables are new and need to be declared with `var`, and which are shared
|
|
||||||
# with the outside.
|
|
||||||
|
|
||||||
# Import the helpers we plan to use.
|
|
||||||
{extend, last} = require './helpers'
|
|
||||||
|
|
||||||
exports.Scope = class Scope
|
|
||||||
|
|
||||||
# The top-level **Scope** object.
|
|
||||||
@root: null
|
|
||||||
|
|
||||||
# Initialize a scope with its parent, for lookups up the chain,
|
|
||||||
# as well as a reference to the **Block** node it belongs to, which is
|
|
||||||
# where it should declare its variables, and a reference to the function that
|
|
||||||
# it wraps.
|
|
||||||
constructor: (@parent, @expressions, @method) ->
|
|
||||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
|
||||||
@positions = {}
|
|
||||||
Scope.root = this unless @parent
|
|
||||||
|
|
||||||
# Adds a new variable or overrides an existing one.
|
|
||||||
add: (name, type, immediate) ->
|
|
||||||
return @parent.add name, type, immediate if @shared and not immediate
|
|
||||||
if Object::hasOwnProperty.call @positions, name
|
|
||||||
@variables[@positions[name]].type = type
|
|
||||||
else
|
|
||||||
@positions[name] = @variables.push({name, type}) - 1
|
|
||||||
|
|
||||||
# When `super` is called, we need to find the name of the current method we're
|
|
||||||
# in, so that we know how to invoke the same method of the parent class. This
|
|
||||||
# can get complicated if super is being called from an inner function.
|
|
||||||
# `namedMethod` will walk up the scope tree until it either finds the first
|
|
||||||
# function object that has a name filled in, or bottoms out.
|
|
||||||
namedMethod: ->
|
|
||||||
return @method if @method.name or !@parent
|
|
||||||
@parent.namedMethod()
|
|
||||||
|
|
||||||
# Look up a variable name in lexical scope, and declare it if it does not
|
|
||||||
# already exist.
|
|
||||||
find: (name) ->
|
|
||||||
return yes if @check name
|
|
||||||
@add name, 'var'
|
|
||||||
no
|
|
||||||
|
|
||||||
# Reserve a variable name as originating from a function parameter for this
|
|
||||||
# scope. No `var` required for internal references.
|
|
||||||
parameter: (name) ->
|
|
||||||
return if @shared and @parent.check name, yes
|
|
||||||
@add name, 'param'
|
|
||||||
|
|
||||||
# Just check to see if a variable has already been declared, without reserving,
|
|
||||||
# walks up to the root scope.
|
|
||||||
check: (name) ->
|
|
||||||
!!(@type(name) or @parent?.check(name))
|
|
||||||
|
|
||||||
# Generate a temporary variable name at the given index.
|
|
||||||
temporary: (name, index) ->
|
|
||||||
if name.length > 1
|
|
||||||
'_' + name + if index > 1 then index - 1 else ''
|
|
||||||
else
|
|
||||||
'_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a'
|
|
||||||
|
|
||||||
# Gets the type of a variable.
|
|
||||||
type: (name) ->
|
|
||||||
return v.type for v in @variables when v.name is name
|
|
||||||
null
|
|
||||||
|
|
||||||
# If we need to store an intermediate result, find an available name for a
|
|
||||||
# compiler-generated variable. `_var`, `_var2`, and so on...
|
|
||||||
freeVariable: (name, reserve=true) ->
|
|
||||||
index = 0
|
|
||||||
index++ while @check((temp = @temporary name, index))
|
|
||||||
@add temp, 'var', yes if reserve
|
|
||||||
temp
|
|
||||||
|
|
||||||
# Ensure that an assignment is made at the top of this scope
|
|
||||||
# (or at the top-level scope, if requested).
|
|
||||||
assign: (name, value) ->
|
|
||||||
@add name, {value, assigned: yes}, yes
|
|
||||||
@hasAssignments = yes
|
|
||||||
|
|
||||||
# Does this scope have any declared variables?
|
|
||||||
hasDeclarations: ->
|
|
||||||
!!@declaredVariables().length
|
|
||||||
|
|
||||||
# Return the list of variables first declared in this scope.
|
|
||||||
declaredVariables: ->
|
|
||||||
realVars = []
|
|
||||||
tempVars = []
|
|
||||||
for v in @variables when v.type is 'var'
|
|
||||||
(if v.name.charAt(0) is '_' then tempVars else realVars).push v.name
|
|
||||||
realVars.sort().concat tempVars.sort()
|
|
||||||
|
|
||||||
# Return the list of assignments that are supposed to be made at the top
|
|
||||||
# of this scope.
|
|
||||||
assignedVariables: ->
|
|
||||||
"#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned
|
|
||||||
117
src/scope.litcoffee
Normal file
117
src/scope.litcoffee
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
The **Scope** class regulates lexical scoping within CoffeeScript. As you
|
||||||
|
generate code, you create a tree of scopes in the same shape as the nested
|
||||||
|
function bodies. Each scope knows about the variables declared within it,
|
||||||
|
and has a reference to its parent enclosing scope. In this way, we know which
|
||||||
|
variables are new and need to be declared with `var`, and which are shared
|
||||||
|
with external scopes.
|
||||||
|
|
||||||
|
Import the helpers we plan to use.
|
||||||
|
|
||||||
|
{extend, last} = require './helpers'
|
||||||
|
|
||||||
|
exports.Scope = class Scope
|
||||||
|
|
||||||
|
The `root` is the top-level **Scope** object for a given file.
|
||||||
|
|
||||||
|
@root: null
|
||||||
|
|
||||||
|
Initialize a scope with its parent, for lookups up the chain,
|
||||||
|
as well as a reference to the **Block** node it belongs to, which is
|
||||||
|
where it should declare its variables, and a reference to the function that
|
||||||
|
it belongs to.
|
||||||
|
|
||||||
|
constructor: (@parent, @expressions, @method) ->
|
||||||
|
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||||
|
@positions = {}
|
||||||
|
Scope.root = this unless @parent
|
||||||
|
|
||||||
|
Adds a new variable or overrides an existing one.
|
||||||
|
|
||||||
|
add: (name, type, immediate) ->
|
||||||
|
return @parent.add name, type, immediate if @shared and not immediate
|
||||||
|
if Object::hasOwnProperty.call @positions, name
|
||||||
|
@variables[@positions[name]].type = type
|
||||||
|
else
|
||||||
|
@positions[name] = @variables.push({name, type}) - 1
|
||||||
|
|
||||||
|
When `super` is called, we need to find the name of the current method we're
|
||||||
|
in, so that we know how to invoke the same method of the parent class. This
|
||||||
|
can get complicated if super is being called from an inner function.
|
||||||
|
`namedMethod` will walk up the scope tree until it either finds the first
|
||||||
|
function object that has a name filled in, or bottoms out.
|
||||||
|
|
||||||
|
namedMethod: ->
|
||||||
|
return @method if @method.name or !@parent
|
||||||
|
@parent.namedMethod()
|
||||||
|
|
||||||
|
Look up a variable name in lexical scope, and declare it if it does not
|
||||||
|
already exist.
|
||||||
|
|
||||||
|
find: (name) ->
|
||||||
|
return yes if @check name
|
||||||
|
@add name, 'var'
|
||||||
|
no
|
||||||
|
|
||||||
|
Reserve a variable name as originating from a function parameter for this
|
||||||
|
scope. No `var` required for internal references.
|
||||||
|
|
||||||
|
parameter: (name) ->
|
||||||
|
return if @shared and @parent.check name, yes
|
||||||
|
@add name, 'param'
|
||||||
|
|
||||||
|
Just check to see if a variable has already been declared, without reserving,
|
||||||
|
walks up to the root scope.
|
||||||
|
|
||||||
|
check: (name) ->
|
||||||
|
!!(@type(name) or @parent?.check(name))
|
||||||
|
|
||||||
|
Generate a temporary variable name at the given index.
|
||||||
|
|
||||||
|
temporary: (name, index) ->
|
||||||
|
if name.length > 1
|
||||||
|
'_' + name + if index > 1 then index - 1 else ''
|
||||||
|
else
|
||||||
|
'_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a'
|
||||||
|
|
||||||
|
Gets the type of a variable.
|
||||||
|
|
||||||
|
type: (name) ->
|
||||||
|
return v.type for v in @variables when v.name is name
|
||||||
|
null
|
||||||
|
|
||||||
|
If we need to store an intermediate result, find an available name for a
|
||||||
|
compiler-generated variable. `_var`, `_var2`, and so on...
|
||||||
|
|
||||||
|
freeVariable: (name, reserve=true) ->
|
||||||
|
index = 0
|
||||||
|
index++ while @check((temp = @temporary name, index))
|
||||||
|
@add temp, 'var', yes if reserve
|
||||||
|
temp
|
||||||
|
|
||||||
|
Ensure that an assignment is made at the top of this scope
|
||||||
|
(or at the top-level scope, if requested).
|
||||||
|
|
||||||
|
assign: (name, value) ->
|
||||||
|
@add name, {value, assigned: yes}, yes
|
||||||
|
@hasAssignments = yes
|
||||||
|
|
||||||
|
Does this scope have any declared variables?
|
||||||
|
|
||||||
|
hasDeclarations: ->
|
||||||
|
!!@declaredVariables().length
|
||||||
|
|
||||||
|
Return the list of variables first declared in this scope.
|
||||||
|
|
||||||
|
declaredVariables: ->
|
||||||
|
realVars = []
|
||||||
|
tempVars = []
|
||||||
|
for v in @variables when v.type is 'var'
|
||||||
|
(if v.name.charAt(0) is '_' then tempVars else realVars).push v.name
|
||||||
|
realVars.sort().concat tempVars.sort()
|
||||||
|
|
||||||
|
Return the list of assignments that are supposed to be made at the top
|
||||||
|
of this scope.
|
||||||
|
|
||||||
|
assignedVariables: ->
|
||||||
|
"#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned
|
||||||
|
|
||||||
|
|
@ -365,3 +365,13 @@ test '#2213: invocations within destructured parameters', ->
|
||||||
throws -> CoffeeScript.compile '({a()})->'
|
throws -> CoffeeScript.compile '({a()})->'
|
||||||
throws -> CoffeeScript.compile '({a:b()})->'
|
throws -> CoffeeScript.compile '({a:b()})->'
|
||||||
throws -> CoffeeScript.compile '({a:b.c()})->'
|
throws -> CoffeeScript.compile '({a:b.c()})->'
|
||||||
|
|
||||||
|
test '#2532: compound assignment with terminator', ->
|
||||||
|
doesNotThrow -> CoffeeScript.compile """
|
||||||
|
a = "hello"
|
||||||
|
a +=
|
||||||
|
"
|
||||||
|
world
|
||||||
|
!
|
||||||
|
"
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -676,3 +676,7 @@ test "#2052: classes should work in strict mode", ->
|
||||||
class A
|
class A
|
||||||
catch e
|
catch e
|
||||||
ok no
|
ok no
|
||||||
|
|
||||||
|
test "#2630: class bodies can't reference arguments", ->
|
||||||
|
throws ->
|
||||||
|
CoffeeScript.compile('class Test then arguments')
|
||||||
|
|
|
||||||
|
|
@ -199,10 +199,17 @@ test "#2258: allow whitespace-style parameter lists in function definitions", ->
|
||||||
a, b, c
|
a, b, c
|
||||||
) -> c
|
) -> c
|
||||||
eq func(1, 2, 3), 3
|
eq func(1, 2, 3), 3
|
||||||
|
|
||||||
func = (
|
func = (
|
||||||
a
|
a
|
||||||
b
|
b
|
||||||
c
|
c
|
||||||
) -> b
|
) -> b
|
||||||
eq func(1, 2, 3), 2
|
eq func(1, 2, 3), 2
|
||||||
|
|
||||||
|
test "#2621: fancy destructuring in parameter lists", ->
|
||||||
|
func = ({ prop1: { key1 }, prop2: { key2, key3: [a, b, c] } }) ->
|
||||||
|
eq(key2, 'key2')
|
||||||
|
eq(a, 'a')
|
||||||
|
|
||||||
|
func({prop1: {key1: 'key1'}, prop2: {key2: 'key2', key3: ['a', 'b', 'c']}})
|
||||||
|
|
|
||||||
48
test/literate.litcoffee
Normal file
48
test/literate.litcoffee
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
Literate CoffeeScript Test
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
comment comment
|
||||||
|
|
||||||
|
test "basic literate CoffeeScript parsing", ->
|
||||||
|
ok yes
|
||||||
|
|
||||||
|
now with a...
|
||||||
|
|
||||||
|
test "broken up indentation", ->
|
||||||
|
|
||||||
|
... broken up ...
|
||||||
|
|
||||||
|
do ->
|
||||||
|
|
||||||
|
... nested block.
|
||||||
|
|
||||||
|
ok yes
|
||||||
|
|
||||||
|
Code in `backticks is not parsed` and...
|
||||||
|
|
||||||
|
test "comments in indented blocks work", ->
|
||||||
|
do ->
|
||||||
|
do ->
|
||||||
|
# Regular comment.
|
||||||
|
|
||||||
|
###
|
||||||
|
Block comment.
|
||||||
|
###
|
||||||
|
|
||||||
|
ok yes
|
||||||
|
|
||||||
|
Regular [Markdown](http://example.com/markdown) features, like links
|
||||||
|
and unordered lists, are fine:
|
||||||
|
|
||||||
|
* I
|
||||||
|
|
||||||
|
* Am
|
||||||
|
|
||||||
|
* A
|
||||||
|
|
||||||
|
* List
|
||||||
|
|
||||||
|
Tabs work too:
|
||||||
|
|
||||||
|
test "tabbed code", ->
|
||||||
|
ok yes
|
||||||
|
|
@ -28,6 +28,12 @@ test "operators should respect new lines as spaced", ->
|
||||||
test "multiple operators should space themselves", ->
|
test "multiple operators should space themselves", ->
|
||||||
eq (+ +1), (- -1)
|
eq (+ +1), (- -1)
|
||||||
|
|
||||||
|
test "compound operators on successive lines", ->
|
||||||
|
a = 1
|
||||||
|
a +=
|
||||||
|
1
|
||||||
|
eq a, 2
|
||||||
|
|
||||||
test "bitwise operators", ->
|
test "bitwise operators", ->
|
||||||
eq 2, (10 & 3)
|
eq 2, (10 & 3)
|
||||||
eq 11, (10 | 3)
|
eq 11, (10 | 3)
|
||||||
|
|
@ -275,16 +281,16 @@ test "#2155 ... conditional assignment to a closure", ->
|
||||||
func = -> x ?= (-> if true then 'hi')
|
func = -> x ?= (-> if true then 'hi')
|
||||||
func()
|
func()
|
||||||
eq x(), 'hi'
|
eq x(), 'hi'
|
||||||
|
|
||||||
test "#2197: Existential existential double trouble", ->
|
test "#2197: Existential existential double trouble", ->
|
||||||
counter = 0
|
counter = 0
|
||||||
func = -> counter++
|
func = -> counter++
|
||||||
func()? ? 100
|
func()? ? 100
|
||||||
eq counter, 1
|
eq counter, 1
|
||||||
|
|
||||||
test "#2567: Optimization of negated existential produces correct result", ->
|
test "#2567: Optimization of negated existential produces correct result", ->
|
||||||
a = 1
|
a = 1
|
||||||
ok !(!a?)
|
ok !(!a?)
|
||||||
ok !b?
|
ok !b?
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue