mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests
This commit is contained in:
@@ -1,7 +1,2 @@
|
||||
# Eat lunch.
|
||||
lunch = eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
# Naive collision detection.
|
||||
for roid, pos in asteroids
|
||||
for roid2 in asteroids when roid isnt roid2
|
||||
roid.explode() if roid.overlaps roid2
|
||||
eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
@@ -517,6 +517,15 @@ coffee --bare --print --stdio</pre>
|
||||
end of your comprehension.
|
||||
</p>
|
||||
<%= code_for('range_comprehensions', 'countdown') %>
|
||||
<p>
|
||||
Note how because we are assigning the value of the comprehensions to a
|
||||
variable in the example above, CoffeeScript is collecting the result of
|
||||
each iteration into an array. Sometimes functions end with loops that are
|
||||
intended to run only for their side-effects. Be careful that you're not
|
||||
accidentally returning the results of the comprehension in these cases,
|
||||
by adding a meaningful return value, like <tt>true</tt>, or <tt>null</tt>,
|
||||
to the bottom of your function.
|
||||
</p>
|
||||
<p>
|
||||
Comprehensions can also be used to iterate over the keys and values in
|
||||
an object. Use <tt>of</tt> to signal comprehension over the properties of
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
var food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref;
|
||||
var food, _i, _len, _ref;
|
||||
_ref = ['toast', 'cheese', 'wine'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
food = _ref[_i];
|
||||
lunch = eat(food);
|
||||
}
|
||||
for (pos = 0, _len2 = asteroids.length; pos < _len2; pos++) {
|
||||
roid = asteroids[pos];
|
||||
for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
|
||||
roid2 = asteroids[_j];
|
||||
if (roid !== roid2) {
|
||||
if (roid.overlaps(roid2)) {
|
||||
roid.explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
eat(food);
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
var numbers, _ref;
|
||||
var numbers;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
([].splice.apply(numbers, [3, 6 - 3 + 1].concat(_ref = [-3, -4, -5, -6])), _ref);
|
||||
[].splice.apply(numbers, [3, 4].concat([-3, -4, -5, -6]));
|
||||
41
index.html
41
index.html
@@ -854,28 +854,12 @@ lyrics = function() {
|
||||
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
|
||||
lunch <span class="Keyword">=</span> eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
|
||||
|
||||
<span class="Comment"><span class="Comment">#</span> Naive collision detection.</span>
|
||||
<span class="Keyword">for</span> roid, pos <span class="Keyword">in</span> asteroids
|
||||
<span class="Keyword">for</span> roid2 <span class="Keyword">in</span> asteroids <span class="Keyword">when</span> roid <span class="Keyword">isnt</span> roid2
|
||||
roid.explode() <span class="Keyword">if</span> roid.overlaps roid2
|
||||
</pre><pre class="idle"><span class="Storage">var</span> food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref;
|
||||
eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
|
||||
</pre><pre class="idle"><span class="Storage">var</span> food, _i, _len, _ref;
|
||||
_ref <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
|
||||
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> _ref.<span class="LibraryConstant">length</span>; _i <span class="Keyword"><</span> _len; _i<span class="Keyword">++</span>) {
|
||||
food <span class="Keyword">=</span> _ref[_i];
|
||||
lunch <span class="Keyword">=</span> eat(food);
|
||||
}
|
||||
<span class="Keyword">for</span> (pos <span class="Keyword">=</span> <span class="Number">0</span>, _len2 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; pos <span class="Keyword"><</span> _len2; pos<span class="Keyword">++</span>) {
|
||||
roid <span class="Keyword">=</span> asteroids[pos];
|
||||
<span class="Keyword">for</span> (_j <span class="Keyword">=</span> <span class="Number">0</span>, _len3 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; _j <span class="Keyword"><</span> _len3; _j<span class="Keyword">++</span>) {
|
||||
roid2 <span class="Keyword">=</span> asteroids[_j];
|
||||
<span class="Keyword">if</span> (roid <span class="Keyword">!</span><span class="Keyword">==</span> roid2) {
|
||||
<span class="Keyword">if</span> (roid.overlaps(roid2)) {
|
||||
roid.explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
eat(food);
|
||||
}
|
||||
</pre><br class='clear' /></div>
|
||||
<p>
|
||||
@@ -901,6 +885,15 @@ countdown = (function() {
|
||||
}
|
||||
return _results;
|
||||
}());;alert(countdown);'>run: countdown</button><br class='clear' /></div>
|
||||
<p>
|
||||
Note how because we are assigning the value of the comprehensions to a
|
||||
variable in the example above, CoffeeScript is collecting the result of
|
||||
each iteration into an array. Sometimes functions end with loops that are
|
||||
intended to run only for their side-effects. Be careful that you're not
|
||||
accidentally returning the results of the comprehension in these cases,
|
||||
by adding a meaningful return value, like <tt>true</tt>, or <tt>null</tt>,
|
||||
to the bottom of your function.
|
||||
</p>
|
||||
<p>
|
||||
Comprehensions can also be used to iterate over the keys and values in
|
||||
an object. Use <tt>of</tt> to signal comprehension over the properties of
|
||||
@@ -975,12 +968,12 @@ middle = copy.slice(3, 6 + 1);;alert(middle);'>run: middle</button><br class='cl
|
||||
numbers[<span class="Number">3</span>..<span class="Number">6</span>] <span class="Keyword">=</span> [<span class="Keyword">-</span><span class="Number">3</span>, <span class="Keyword">-</span><span class="Number">4</span>, <span class="Keyword">-</span><span class="Number">5</span>, <span class="Keyword">-</span><span class="Number">6</span>]
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Storage">var</span> numbers, _ref;
|
||||
</pre><pre class="idle"><span class="Storage">var</span> numbers;
|
||||
numbers <span class="Keyword">=</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>];
|
||||
([].splice.<span class="LibraryFunction">apply</span>(numbers, [<span class="Number">3</span>, <span class="Number">6</span> <span class="Keyword">-</span> <span class="Number">3</span> <span class="Keyword">+</span> <span class="Number">1</span>].<span class="LibraryFunction">concat</span>(_ref <span class="Keyword">=</span> [<span class="Keyword">-</span><span class="Number">3</span>, <span class="Keyword">-</span><span class="Number">4</span>, <span class="Keyword">-</span><span class="Number">5</span>, <span class="Keyword">-</span><span class="Number">6</span>])), _ref);
|
||||
</pre><button onclick='javascript: var numbers, _ref;
|
||||
[].splice.<span class="LibraryFunction">apply</span>(numbers, [<span class="Number">3</span>, <span class="Number">4</span>].<span class="LibraryFunction">concat</span>([<span class="Keyword">-</span><span class="Number">3</span>, <span class="Keyword">-</span><span class="Number">4</span>, <span class="Keyword">-</span><span class="Number">5</span>, <span class="Keyword">-</span><span class="Number">6</span>]));
|
||||
</pre><button onclick='javascript: var numbers;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
([].splice.apply(numbers, [3, 6 - 3 + 1].concat(_ref = [-3, -4, -5, -6])), _ref);;alert(numbers);'>run: numbers</button><br class='clear' /></div>
|
||||
[].splice.apply(numbers, [3, 4].concat([-3, -4, -5, -6]));;alert(numbers);'>run: numbers</button><br class='clear' /></div>
|
||||
<p>
|
||||
Note that JavaScript strings are immutable, and can't be spliced.
|
||||
</p>
|
||||
@@ -1920,7 +1913,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
works like <tt>null</tt>, and cannot be assigned a new value.
|
||||
There was a precedence change with respect to single-line comprehensions:
|
||||
<tt>result = i for i in list</tt><br /> used to parse as <tt>result = (i for i in list)</tt>
|
||||
by default ... it now parses as <br /ea><tt>(result = i) for i in list</tt>.
|
||||
by default ... it now parses as <br /><tt>(result = i) for i in list</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
(function() {
|
||||
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref;
|
||||
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
util = require('util');
|
||||
helpers = require('./helpers');
|
||||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
@@ -55,7 +56,7 @@
|
||||
return compileScripts();
|
||||
};
|
||||
compileScripts = function() {
|
||||
var base, compile, _fn, _i, _len, _results;
|
||||
var base, compile, source, _fn, _i, _len, _results;
|
||||
_fn = function(source) {
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
@@ -185,7 +186,7 @@
|
||||
if (err) {
|
||||
return printLine(err.message);
|
||||
} else if (opts.compile && opts.watch) {
|
||||
return printLine("Compiled " + source);
|
||||
return util.log("compiled " + source);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
37
lib/nodes.js
37
lib/nodes.js
@@ -520,7 +520,13 @@
|
||||
__extends(Call, Base);
|
||||
Call.prototype.children = ['variable', 'args'];
|
||||
Call.prototype.newInstance = function() {
|
||||
this.isNew = true;
|
||||
var base;
|
||||
base = this.variable.base || this.variable;
|
||||
if (base instanceof Call) {
|
||||
base.newInstance();
|
||||
} else {
|
||||
this.isNew = true;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Call.prototype.superReference = function(o) {
|
||||
@@ -1198,9 +1204,12 @@
|
||||
return !!this.ctor;
|
||||
};
|
||||
Code.prototype.compileNode = function(o) {
|
||||
var code, exprs, i, idt, lit, p, param, ref, scope, sharedScope, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref, _ref2, _ref3, _ref4, _results;
|
||||
var code, exprs, i, idt, lit, p, param, ref, sharedScope, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref, _ref2, _ref3, _ref4, _results;
|
||||
sharedScope = del(o, 'sharedScope');
|
||||
o.scope = scope = sharedScope || new Scope(o.scope, this.body, this);
|
||||
o.scope = sharedScope || new Scope(o.scope, this.body, this);
|
||||
if (sharedScope) {
|
||||
o.scope.shared = true;
|
||||
}
|
||||
o.indent += TAB;
|
||||
delete o.bare;
|
||||
delete o.globals;
|
||||
@@ -1253,7 +1262,7 @@
|
||||
if (!splats) {
|
||||
for (i = 0, _len4 = vars.length; i < _len4; i++) {
|
||||
v = vars[i];
|
||||
scope.parameter(vars[i] = v.compile(o));
|
||||
o.scope.parameter(vars[i] = v.compile(o));
|
||||
}
|
||||
}
|
||||
if (!(wasEmpty || this.noReturn)) {
|
||||
@@ -1763,17 +1772,15 @@
|
||||
scope = o.scope;
|
||||
name = this.name && this.name.compile(o, LEVEL_LIST);
|
||||
index = this.index && this.index.compile(o, LEVEL_LIST);
|
||||
if (!hasCode) {
|
||||
if (name && !this.pattern) {
|
||||
scope.find(name, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (index) {
|
||||
scope.find(index, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (name && !this.pattern) {
|
||||
scope.find(name, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (index) {
|
||||
scope.find(index, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (this.returns && !hasPure) {
|
||||
rvar = scope.freeVariable('results');
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
(function() {
|
||||
var CoffeeScript, helpers, readline, repl, run, stdio;
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdio;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
readline = require('readline');
|
||||
stdio = process.openStdin();
|
||||
error = function(err) {
|
||||
return stdio.write((err.stack || err.toString()) + '\n\n');
|
||||
};
|
||||
helpers.extend(global, {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
@@ -21,10 +24,11 @@
|
||||
console.log(val);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.stack || err.toString());
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
repl = readline.createInterface(stdio);
|
||||
repl.setPrompt('coffee> ');
|
||||
stdio.on('data', function(buffer) {
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
return false;
|
||||
};
|
||||
Scope.prototype.parameter = function(name) {
|
||||
if (this.shared && this.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
Scope.prototype.check = function(name, immediate) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# External dependencies.
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
util = require 'util'
|
||||
helpers = require './helpers'
|
||||
optparse = require './optparse'
|
||||
CoffeeScript = require './coffee-script'
|
||||
@@ -154,7 +155,7 @@ writeJs = (source, js, base) ->
|
||||
js = ' ' if js.length <= 0
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
if err then printLine err.message
|
||||
else if opts.compile and opts.watch then printLine "Compiled #{source}"
|
||||
else if opts.compile and opts.watch then util.log "compiled #{source}"
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p #{dir}", compile
|
||||
|
||||
|
||||
@@ -433,7 +433,11 @@ exports.Call = class Call extends Base
|
||||
|
||||
# Tag this invocation as creating a new instance.
|
||||
newInstance: ->
|
||||
@isNew = true
|
||||
base = @variable.base or @variable
|
||||
if base instanceof Call
|
||||
base.newInstance()
|
||||
else
|
||||
@isNew = true
|
||||
this
|
||||
|
||||
# Grab the reference to the superclass's implementation of the current
|
||||
@@ -978,9 +982,10 @@ exports.Code = class Code extends Base
|
||||
# arrow, generates a wrapper that saves the current value of `this` through
|
||||
# a closure.
|
||||
compileNode: (o) ->
|
||||
sharedScope = del o, 'sharedScope'
|
||||
o.scope = scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.indent += TAB
|
||||
sharedScope = del o, 'sharedScope'
|
||||
o.scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.scope.shared = yes if sharedScope
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
vars = []
|
||||
@@ -1004,7 +1009,7 @@ exports.Code = class Code extends Base
|
||||
wasEmpty = @body.isEmpty()
|
||||
exprs.unshift splats if splats
|
||||
@body.expressions.unshift exprs... if exprs.length
|
||||
scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
@body.makeReturn() unless wasEmpty or @noReturn
|
||||
idt = o.indent
|
||||
code = 'function'
|
||||
@@ -1421,9 +1426,8 @@ exports.For = class For extends Base
|
||||
scope = o.scope
|
||||
name = @name and @name.compile o, LEVEL_LIST
|
||||
index = @index and @index.compile o, LEVEL_LIST
|
||||
unless hasCode
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
rvar = scope.freeVariable 'results' if @returns and not hasPure
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
varPart = ''
|
||||
|
||||
@@ -12,6 +12,10 @@ readline = require 'readline'
|
||||
# Start by opening up **stdio**.
|
||||
stdio = process.openStdin()
|
||||
|
||||
# Log an error.
|
||||
error = (err) ->
|
||||
stdio.write (err.stack or err.toString()) + '\n\n'
|
||||
|
||||
# Quick alias for quitting the REPL.
|
||||
helpers.extend global, quit: -> process.exit(0)
|
||||
|
||||
@@ -23,9 +27,12 @@ run = (buffer) ->
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
|
||||
console.log val if val isnt undefined
|
||||
catch err
|
||||
console.error err.stack or err.toString()
|
||||
error err
|
||||
repl.prompt()
|
||||
|
||||
# Make sure that uncaught exceptions don't kill the REPL.
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
# Create the REPL by listening to **stdin**.
|
||||
repl = readline.createInterface stdio
|
||||
repl.setPrompt 'coffee> '
|
||||
|
||||
@@ -44,6 +44,7 @@ exports.Scope = class Scope
|
||||
# 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 @check name, yes
|
||||
@add name, 'param'
|
||||
|
||||
# Just check to see if a variable has already been declared, without reserving,
|
||||
|
||||
@@ -227,4 +227,17 @@ foo = ->
|
||||
for j in [0..7]
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
@@ -346,6 +346,7 @@ eq ok, new ->
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
|
||||
#855: execution context for `func arr...` should be `null`
|
||||
(->
|
||||
global = @
|
||||
@@ -355,3 +356,14 @@ eq ok, new ->
|
||||
contextTest.apply null, array
|
||||
contextTest array...
|
||||
)()
|
||||
|
||||
|
||||
# #894: Splatting against constructor-chained functions.
|
||||
x = null
|
||||
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
|
||||
new Foo().bar([101]...)
|
||||
|
||||
eq x, 101
|
||||
Reference in New Issue
Block a user