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
|
@ -1,6 +1,7 @@
|
|||
raw
|
||||
presentation
|
||||
test.coffee
|
||||
test.litcoffee
|
||||
parser.output
|
||||
test/fixtures/underscore
|
||||
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) ->
|
||||
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
|
||||
|
||||
|
||||
|
@ -119,8 +119,7 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
|||
}(this));
|
||||
"""
|
||||
unless process.env.MINIFY is 'false'
|
||||
{parser, uglify} = require 'uglify-js'
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code
|
||||
{code} = require('uglify-js').minify code, fromString: true
|
||||
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
||||
console.log "built ... running browser tests:"
|
||||
invoke 'test:browser'
|
||||
|
@ -227,11 +226,12 @@ runTests = (CoffeeScript) ->
|
|||
|
||||
# Run every test in the `test` folder, recording failures.
|
||||
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
|
||||
code = fs.readFileSync filename
|
||||
try
|
||||
CoffeeScript.run code.toString(), {filename}
|
||||
CoffeeScript.run code.toString(), {filename, literate}
|
||||
catch error
|
||||
failures.push {filename, error}
|
||||
return !failures.length
|
||||
|
|
|
@ -127,8 +127,8 @@
|
|||
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
|
||||
no interpretation at runtime. You can use any existing JavaScript library
|
||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||
readable and pretty-printed, passes through
|
||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||
readable and pretty-printed, passes through
|
||||
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||
without warnings, will work in every JavaScript runtime, and tends
|
||||
to run as fast or faster than the equivalent handwritten JavaScript.
|
||||
|
@ -176,7 +176,7 @@ npm install -g coffee-script</pre>
|
|||
<p>
|
||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest <b>master</b> version of CoffeeScript, you
|
||||
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>
|
||||
|
||||
<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:
|
||||
</p>
|
||||
|
||||
|
@ -288,7 +288,7 @@ sudo bin/cake install</pre>
|
|||
<tr>
|
||||
<td><code>-b, --bare</code></td>
|
||||
<td>
|
||||
Compile the JavaScript without the
|
||||
Compile the JavaScript without the
|
||||
<a href="#lexical_scope">top-level function safety wrapper</a>.
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -318,8 +318,9 @@ Expressions
|
|||
<td><code>--nodejs</code></td>
|
||||
<td>
|
||||
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
|
||||
flag to forward options directly to Node.js.
|
||||
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt>, <tt>--max-stack-size</tt>,
|
||||
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>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -980,11 +981,11 @@ Expressions
|
|||
portions in CoffeeScript.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>
|
||||
Screencasts
|
||||
</h2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<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>
|
||||
Examples
|
||||
</h2>
|
||||
|
||||
|
||||
<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
|
||||
to throw out few more:
|
||||
</p>
|
||||
|
@ -1115,7 +1116,7 @@ Expressions
|
|||
<span id="changelog" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
|
||||
<p>
|
||||
<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>
|
||||
|
@ -1123,7 +1124,7 @@ Expressions
|
|||
</b>
|
||||
<ul>
|
||||
<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.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -1131,12 +1132,12 @@ Expressions
|
|||
and moving from <tt>path.exists</tt> to <tt>fs.exists</tt>.
|
||||
</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.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<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>
|
||||
|
@ -1146,7 +1147,7 @@ Expressions
|
|||
<li>
|
||||
Due to the new semantics of JavaScript's strict mode, CoffeeScript no
|
||||
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.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -1165,7 +1166,7 @@ Expressions
|
|||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<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>
|
||||
|
@ -1173,26 +1174,26 @@ Expressions
|
|||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
CoffeeScript now enforces all of JavaScript's <b>Strict Mode</b> early syntax
|
||||
errors at compile time. This includes old-style octal literals,
|
||||
duplicate property names in object literals, duplicate parameters in
|
||||
CoffeeScript now enforces all of JavaScript's <b>Strict Mode</b> early syntax
|
||||
errors at compile time. This includes old-style octal literals,
|
||||
duplicate property names in object literals, duplicate parameters in
|
||||
a function definition, deleting naked variables, setting the value of
|
||||
<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>.
|
||||
</li>
|
||||
<li>
|
||||
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
|
||||
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.
|
||||
</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.
|
||||
</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.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -1204,18 +1205,18 @@ Expressions
|
|||
between them.
|
||||
</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.
|
||||
</li>
|
||||
<li>
|
||||
Additional tweaks and improvments to <tt>coffee --watch</tt> under
|
||||
Node's "new" file watching API. Watch will now beep by default
|
||||
Additional tweaks and improvments to <tt>coffee --watch</tt> under
|
||||
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
|
||||
ignore hidden directories by default when watching recursively.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<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>
|
||||
|
@ -1242,7 +1243,7 @@ Expressions
|
|||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<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>
|
||||
|
@ -1254,7 +1255,7 @@ Expressions
|
|||
out and keep it readable, as you can see in the examples on this page.
|
||||
</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.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -1263,7 +1264,7 @@ Expressions
|
|||
also supports binary numbers: <tt>0b10 is 2</tt>.
|
||||
</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
|
||||
having to use <b>npm</b>. For example, after adding the CoffeeScript
|
||||
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.
|
||||
</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.
|
||||
</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/geraldalewis">@geraldalewis</a></b>,
|
||||
<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() {
|
||||
var CoffeeScript, runScripts;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
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() {
|
||||
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;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
Lexer = require('./lexer').Lexer;
|
||||
|
||||
parser = require('./parser').parser;
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
stripBOM = function(content) {
|
||||
if (content.charCodeAt(0) === 0xFEFF) {
|
||||
return content.substring(1);
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
extensions = ['.coffee', '.litcoffee'];
|
||||
|
||||
loadFile = function(module, filename) {
|
||||
var raw, stripped;
|
||||
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) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
var content;
|
||||
content = compile(stripBOM(fs.readFileSync(filename, 'utf8')), {
|
||||
filename: filename
|
||||
});
|
||||
return module._compile(content, filename);
|
||||
};
|
||||
for (_i = 0, _len = extensions.length; _i < _len; _i++) {
|
||||
ext = extensions[_i];
|
||||
require.extensions[ext] = loadFile;
|
||||
}
|
||||
}
|
||||
|
||||
exports.VERSION = '1.4.0';
|
||||
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.VERSION = '1.5.0-pre';
|
||||
|
||||
exports.helpers = require('./helpers');
|
||||
|
||||
|
@ -44,7 +43,7 @@
|
|||
}
|
||||
merge = exports.helpers.merge;
|
||||
try {
|
||||
js = (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
js = (parser.parse(lexer.tokenize(code, options))).compile(options);
|
||||
if (!options.header) {
|
||||
return js;
|
||||
}
|
||||
|
@ -71,7 +70,7 @@
|
|||
};
|
||||
|
||||
exports.run = function(code, options) {
|
||||
var mainModule;
|
||||
var mainModule, _ref;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -79,7 +78,7 @@
|
|||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||
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);
|
||||
} else {
|
||||
return mainModule._compile(code, mainModule.filename);
|
||||
|
@ -87,7 +86,7 @@
|
|||
};
|
||||
|
||||
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) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -101,10 +100,10 @@
|
|||
sandbox = options.sandbox;
|
||||
} else {
|
||||
sandbox = Script.createContext();
|
||||
_ref1 = options.sandbox;
|
||||
for (k in _ref1) {
|
||||
if (!__hasProp.call(_ref1, k)) continue;
|
||||
v = _ref1[k];
|
||||
_ref = options.sandbox;
|
||||
for (k in _ref) {
|
||||
if (!__hasProp.call(_ref, k)) continue;
|
||||
v = _ref[k];
|
||||
sandbox[k] = v;
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +120,9 @@
|
|||
return Module._load(path, _module, true);
|
||||
};
|
||||
_module.filename = sandbox.__filename;
|
||||
_ref2 = Object.getOwnPropertyNames(require);
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
r = _ref2[_i];
|
||||
_ref1 = Object.getOwnPropertyNames(require);
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
r = _ref1[_j];
|
||||
if (r !== 'paths') {
|
||||
_require[r] = require[r];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(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');
|
||||
|
||||
|
@ -48,6 +49,8 @@
|
|||
|
||||
optionParser = null;
|
||||
|
||||
coffee_exts = ['.coffee', '.litcoffee'];
|
||||
|
||||
exports.run = function() {
|
||||
var literals, source, _i, _len, _results;
|
||||
parseOptions();
|
||||
|
@ -92,11 +95,12 @@
|
|||
|
||||
compilePath = function(source, topLevel, base) {
|
||||
return fs.stat(source, function(err, stats) {
|
||||
var _ref1, _ref2;
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
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";
|
||||
return compilePath(source, topLevel, base);
|
||||
}
|
||||
|
@ -111,7 +115,7 @@
|
|||
watchDir(source, base);
|
||||
}
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var file, index, _ref1, _ref2;
|
||||
var file, index, _ref2, _ref3;
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
|
@ -122,7 +126,7 @@
|
|||
files = files.filter(function(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;
|
||||
_results = [];
|
||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||
|
@ -130,15 +134,15 @@
|
|||
_results.push(path.join(source, file));
|
||||
}
|
||||
return _results;
|
||||
})())), _ref1;
|
||||
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() {
|
||||
})())), _ref2;
|
||||
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref3 = files.map(function() {
|
||||
return null;
|
||||
}))), _ref2;
|
||||
}))), _ref3;
|
||||
return files.forEach(function(file) {
|
||||
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) {
|
||||
watch(source, base);
|
||||
}
|
||||
|
@ -170,9 +174,9 @@
|
|||
};
|
||||
CoffeeScript.emit('compile', task);
|
||||
if (o.tokens) {
|
||||
return printTokens(CoffeeScript.tokens(t.input));
|
||||
return printTokens(CoffeeScript.tokens(t.input, t.options));
|
||||
} 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) {
|
||||
return CoffeeScript.run(t.input, t.options);
|
||||
} else if (o.join && t.file !== o.join) {
|
||||
|
@ -472,8 +476,11 @@
|
|||
};
|
||||
|
||||
compileOptions = function(filename) {
|
||||
var literate;
|
||||
literate = path.extname(filename) === '.litcoffee';
|
||||
return {
|
||||
filename: filename,
|
||||
literate: literate,
|
||||
bare: opts.bare,
|
||||
header: opts.compile
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
||||
|
||||
|
@ -575,6 +575,9 @@
|
|||
}), o('SimpleAssignable COMPOUND_ASSIGN\
|
||||
INDENT Expression OUTDENT', function() {
|
||||
return new Assign($1, $4, $2);
|
||||
}), o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR\
|
||||
Expression', function() {
|
||||
return new Assign($1, $4, $2);
|
||||
}), o('SimpleAssignable EXTENDS Expression', function() {
|
||||
return new Extends($1, $3);
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
var buildLocationData, extend, flatten, _ref;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
var key, val, _ref;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(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; };
|
||||
|
||||
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
|
||||
|
@ -16,19 +16,16 @@
|
|||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
if (WHITESPACE.test(code)) {
|
||||
code = "\n" + code;
|
||||
}
|
||||
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
||||
this.code = code;
|
||||
this.chunkLine = opts.line || 0;
|
||||
this.chunkColumn = opts.column || 0;
|
||||
this.literate = opts.literate;
|
||||
code = this.clean(code);
|
||||
this.indent = 0;
|
||||
this.indebt = 0;
|
||||
this.outdebt = 0;
|
||||
this.indents = [];
|
||||
this.ends = [];
|
||||
this.tokens = [];
|
||||
this.chunkLine = opts.line || 0;
|
||||
this.chunkColumn = opts.column || 0;
|
||||
i = 0;
|
||||
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();
|
||||
|
@ -45,6 +42,35 @@
|
|||
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() {
|
||||
var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||
|
@ -486,7 +512,7 @@
|
|||
if (HEREDOC_ILLEGAL.test(doc)) {
|
||||
this.error("block comment cannot contain \"*/\", starting");
|
||||
}
|
||||
if (doc.indexOf('\n') <= 0) {
|
||||
if (doc.indexOf('\n') < 0) {
|
||||
return doc;
|
||||
}
|
||||
} else {
|
||||
|
@ -804,6 +830,8 @@
|
|||
|
||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
|
||||
|
||||
BOM = 65279;
|
||||
|
||||
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;
|
||||
|
@ -814,7 +842,9 @@
|
|||
|
||||
WHITESPACE = /^[^\n\S]+/;
|
||||
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
|
||||
LITERATE = /^([ ]{4}|\t)/;
|
||||
|
||||
CODE = /^[-=]>/;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(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,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
|
@ -1937,7 +1937,7 @@
|
|||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
obj = _ref2[_i];
|
||||
if (obj instanceof Assign) {
|
||||
names.push(obj.value.unwrap().value);
|
||||
names.push.apply(names, this.names(obj.value.unwrap()));
|
||||
} else if (obj instanceof Splat) {
|
||||
names.push(obj.name.unwrap().value);
|
||||
} else if (obj instanceof Value) {
|
||||
|
@ -2904,6 +2904,9 @@
|
|||
func = new Code([], Block.wrap([expressions]));
|
||||
args = [];
|
||||
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');
|
||||
args = [new Literal('this')];
|
||||
if (mentionsArgs) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
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() {
|
||||
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; };
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(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,
|
||||
__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() {
|
||||
var Scope, extend, last, _ref;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.4.0
|
||||
// Generated by CoffeeScript 1.5.0-pre
|
||||
(function() {
|
||||
var BASE64_CHARS, LineMapping, MAX_BASE64_VALUE, VLQ_CONTINUATION_BIT, VLQ_MASK, VLQ_SHIFT, encodeBase64Char;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0-pre",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
|
||||
|
@ -29,7 +29,7 @@
|
|||
"url": "git://github.com/jashkenas/coffee-script.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"uglify-js": ">=1.0.0",
|
||||
"uglify-js": "~2.2",
|
||||
"jison": ">=0.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,25 +6,27 @@
|
|||
# If included on a webpage, it will automatically sniff out, compile, and
|
||||
# execute all scripts present in `text/coffeescript` tags.
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer,RESERVED} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
vm = require 'vm'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
vm = require 'vm'
|
||||
|
||||
stripBOM = (content) ->
|
||||
if content.charCodeAt(0) is 0xFEFF then content.substring 1 else content
|
||||
# The file extensions that are considered to be CoffeeScript.
|
||||
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
|
||||
require.extensions['.coffee'] = (module, filename) ->
|
||||
content = compile stripBOM(fs.readFileSync filename, 'utf8'), {filename}
|
||||
module._compile content, filename
|
||||
for ext in extensions
|
||||
require.extensions[ext] = loadFile
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.4.0'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
exports.VERSION = '1.5.0-pre'
|
||||
|
||||
# Expose helpers for testing.
|
||||
exports.helpers = require './helpers'
|
||||
|
@ -34,7 +36,7 @@ exports.helpers = require './helpers'
|
|||
exports.compile = compile = (code, options = {}) ->
|
||||
{merge} = exports.helpers
|
||||
try
|
||||
js = (parser.parse lexer.tokenize code).compile options
|
||||
js = (parser.parse lexer.tokenize(code, options)).compile options
|
||||
return js unless options.header
|
||||
catch err
|
||||
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
|
||||
|
||||
# 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
|
||||
else
|
||||
mainModule._compile code, mainModule.filename
|
||||
|
|
|
@ -57,6 +57,7 @@ sourceCode = []
|
|||
notSources = {}
|
||||
watchers = {}
|
||||
optionParser = null
|
||||
coffee_exts = ['.coffee', '.litcoffee']
|
||||
|
||||
# Run `coffee` by parsing passed options and determining what action to take.
|
||||
# Many flags cause us to divert before compiling anything. Flags passed after
|
||||
|
@ -81,13 +82,13 @@ exports.run = ->
|
|||
compilePath source, yes, path.normalize source
|
||||
|
||||
# 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
|
||||
# and all subdirectories.
|
||||
# is passed, recursively compile all '.coffee' and '.litcoffee' extension source
|
||||
# files in it and all subdirectories.
|
||||
compilePath = (source, topLevel, base) ->
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err and err.code isnt '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"
|
||||
return compilePath source, topLevel, base
|
||||
if topLevel
|
||||
|
@ -105,7 +106,7 @@ compilePath = (source, topLevel, base) ->
|
|||
sourceCode[index..index] = files.map -> null
|
||||
files.forEach (file) ->
|
||||
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
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err and err.code isnt 'ENOENT'
|
||||
|
@ -125,8 +126,8 @@ compileScript = (file, input, base) ->
|
|||
try
|
||||
t = task = {file, input, options}
|
||||
CoffeeScript.emit 'compile', task
|
||||
if o.tokens then printTokens CoffeeScript.tokens t.input
|
||||
else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim()
|
||||
if o.tokens then printTokens CoffeeScript.tokens t.input, t.options
|
||||
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.join and t.file isnt o.join
|
||||
sourceCode[sources.indexOf(t.file)] = t.input
|
||||
|
@ -318,7 +319,8 @@ parseOptions = ->
|
|||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
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
|
||||
# the `node` binary, preserving the other options.
|
||||
|
|
|
@ -558,6 +558,8 @@ grammar =
|
|||
Expression', -> new Assign $1, $3, $2
|
||||
o 'SimpleAssignable COMPOUND_ASSIGN
|
||||
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
|
||||
]
|
||||
|
||||
|
|
|
@ -32,20 +32,19 @@ exports.Lexer = class Lexer
|
|||
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||
# unless explicitly asked not to.
|
||||
tokenize: (code, opts = {}) ->
|
||||
code = "\n#{code}" if WHITESPACE.test code
|
||||
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
||||
@literate = opts.literate # Are we lexing literate CoffeeScript?
|
||||
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 =
|
||||
opts.line or 0 # The start line for the current chunk.
|
||||
opts.line or 0 # The start line for the current @chunk.
|
||||
@chunkColumn =
|
||||
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]`.
|
||||
opts.column or 0 # The start column of the current @chunk.
|
||||
|
||||
# At every position, run through this list of attempted matches,
|
||||
# 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
|
||||
(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
|
||||
# ----------
|
||||
|
||||
|
@ -87,6 +102,7 @@ exports.Lexer = class Lexer
|
|||
return 0 unless match = IDENTIFIER.exec @chunk
|
||||
[input, id, colon] = match
|
||||
|
||||
# Preserve lenght of id for location data
|
||||
idLength = id.length
|
||||
poppedToken = undefined
|
||||
|
||||
|
@ -417,7 +433,7 @@ exports.Lexer = class Lexer
|
|||
if herecomment
|
||||
if HEREDOC_ILLEGAL.test doc
|
||||
@error "block comment cannot contain \"*/\", starting"
|
||||
return doc if doc.indexOf('\n') <= 0
|
||||
return doc if doc.indexOf('\n') < 0
|
||||
else
|
||||
while match = HEREDOC_INDENT.exec doc
|
||||
attempt = match[1]
|
||||
|
@ -596,6 +612,8 @@ exports.Lexer = class Lexer
|
|||
# -------
|
||||
|
||||
# Returns the line and column number from an offset into the current chunk.
|
||||
#
|
||||
# `offset` is a number of characters into @chunk.
|
||||
getLineAndColumnFromChunk: (offset) ->
|
||||
if offset is 0
|
||||
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.STRICT_PROSCRIBED = STRICT_PROSCRIBED
|
||||
|
||||
# The character code of the nasty Microsoft madness otherwise known as the BOM.
|
||||
BOM = 65279
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER = /// ^
|
||||
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
|
||||
|
@ -751,7 +772,9 @@ OPERATOR = /// ^ (
|
|||
|
||||
WHITESPACE = /^[^\n\S]+/
|
||||
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/
|
||||
|
||||
LITERATE = /^([ ]{4}|\t)/
|
||||
|
||||
CODE = /^[-=]>/
|
||||
|
||||
|
|
|
@ -1307,7 +1307,7 @@ exports.Param = class Param extends Base
|
|||
for obj in name.objects
|
||||
# * assignments within destructured parameters `{foo:bar}`
|
||||
if obj instanceof Assign
|
||||
names.push obj.value.unwrap().value
|
||||
names.push @names(obj.value.unwrap())...
|
||||
# * splats within destructured parameters `[xs...]`
|
||||
else if obj instanceof Splat
|
||||
names.push obj.name.unwrap().value
|
||||
|
@ -1952,6 +1952,8 @@ Closure =
|
|||
func = new Code [], Block.wrap [expressions]
|
||||
args = []
|
||||
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'
|
||||
args = [new Literal 'this']
|
||||
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
|
|
@ -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:b()})->'
|
||||
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
|
||||
catch e
|
||||
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
|
||||
) -> c
|
||||
eq func(1, 2, 3), 3
|
||||
|
||||
|
||||
func = (
|
||||
a
|
||||
b
|
||||
c
|
||||
) -> 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']}})
|
||||
|
|
|
@ -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", ->
|
||||
eq (+ +1), (- -1)
|
||||
|
||||
test "compound operators on successive lines", ->
|
||||
a = 1
|
||||
a +=
|
||||
1
|
||||
eq a, 2
|
||||
|
||||
test "bitwise operators", ->
|
||||
eq 2, (10 & 3)
|
||||
eq 11, (10 | 3)
|
||||
|
@ -275,16 +281,16 @@ test "#2155 ... conditional assignment to a closure", ->
|
|||
func = -> x ?= (-> if true then 'hi')
|
||||
func()
|
||||
eq x(), 'hi'
|
||||
|
||||
|
||||
test "#2197: Existential existential double trouble", ->
|
||||
counter = 0
|
||||
func = -> counter++
|
||||
func()? ? 100
|
||||
eq counter, 1
|
||||
|
||||
|
||||
test "#2567: Optimization of negated existential produces correct result", ->
|
||||
a = 1
|
||||
ok !(!a?)
|
||||
ok !b?
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue