Compare commits

..

3 Commits
2.2.0 ... 2.2.1

Author SHA1 Message Date
Geoffrey Booth
a73f66bc11 2.2.1 (#4885)
* 2.2.1 changelog

* Bump version to 2.2.1 and update output
2018-02-06 22:28:15 -08:00
zdenko
ba094126e2 Fix #4882: Range not declaring var for the "i" (#4883)
* fix #4882

* test
2018-02-04 13:33:08 -08:00
zdenko
794f65fbd7 Fix #4878: Compile error when using destructuring with a splat or expansion in an array (#4879)
* fix #4878

* improvements

* test

* refactor
2018-02-03 13:35:41 -08:00
24 changed files with 169 additions and 53 deletions

View File

@@ -2947,7 +2947,11 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
idx = del o, <span class="hljs-string">'index'</span>
idxName = del o, <span class="hljs-string">'name'</span>
namedIndex = idxName <span class="hljs-keyword">and</span> idxName <span class="hljs-keyword">isnt</span> idx
varPart = <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
varPart =
<span class="hljs-keyword">if</span> known <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> namedIndex
<span class="hljs-string">"var <span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@toC}</span>"</span> <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@step}</span>"</span> <span class="hljs-keyword">if</span> @step <span class="hljs-keyword">isnt</span> @stepVar
[lt, gt] = [<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &lt;<span class="hljs-subst">#{@equals}</span>"</span>, <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &gt;<span class="hljs-subst">#{@equals}</span>"</span>]</pre></div></div>
@@ -4955,8 +4959,8 @@ Examples: [a, b, c…, d, e, f…], [a, b, …, c, d, …], [a, b, …, c, d, e
<div class="content"><div class='highlight'><pre> objects[splatsAndExpans.sort()[<span class="hljs-number">1</span>]].error <span class="hljs-string">"multiple splats/expansions are disallowed in an assignment"</span>
isSplat = splats.length
isExpans = expans.length
isSplat = splats?.length &gt; <span class="hljs-number">0</span>
isExpans = expans?.length &gt; <span class="hljs-number">0</span>
isObject = @variable.isObject()
isArray = @variable.isArray()
@@ -5101,7 +5105,7 @@ Examples: [a, b, {c, r…}, d], [a, …, {b, r…}, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">loopObjects</span> = <span class="hljs-params">(objs, vvarTxt)</span> =&gt;</span>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">loopObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
objSpreads = hasObjSpreads objs
<span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs</pre></div></div>
@@ -5182,16 +5186,16 @@ Examples: [a, b, {c, r…}, d], [a, …, {b, r…}, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">assignObjects</span> = <span class="hljs-params">(objs, vvarTxt)</span> =&gt;</span>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">assignObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
vvar = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Arr(objs, <span class="hljs-literal">yes</span>)
vval = <span class="hljs-keyword">if</span> vvarTxt <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">then</span> vvarTxt <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarTxt)
assigns.push <span class="hljs-keyword">new</span> Assign(vvar, vval, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST
<span class="hljs-function">
<span class="hljs-title">processObjects</span> = <span class="hljs-params">(objs, vvarTxt)</span> -&gt;</span>
<span class="hljs-title">processObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> -&gt;</span>
<span class="hljs-keyword">if</span> complexObjects objs
loopObjects objs, vvarTxt
loopObjects objs, vvar, vvarTxt
<span class="hljs-keyword">else</span>
assignObjects objs, vvarTxt</pre></div></div>
assignObjects objs, vvar, vvarTxt</pre></div></div>
</li>
@@ -5220,7 +5224,7 @@ b) <code>Expansion</code>
expIdx = splatsAndExpans[<span class="hljs-number">0</span>]
leftObjs = objects.slice <span class="hljs-number">0</span>, expIdx + (<span class="hljs-keyword">if</span> isSplat <span class="hljs-keyword">then</span> <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-number">0</span>)
rightObjs = objects.slice expIdx + <span class="hljs-number">1</span>
processObjects leftObjs, vvarText <span class="hljs-keyword">if</span> leftObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
processObjects leftObjs, vvar, vvarText <span class="hljs-keyword">if</span> leftObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> rightObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span></pre></div></div>
</li>
@@ -5243,7 +5247,7 @@ b) <code>Expansion</code>
restVar = refExp
refExp = o.scope.freeVariable <span class="hljs-string">'ref'</span>
assigns.push [@makeCode(refExp + <span class="hljs-string">' = '</span>), restVar.compileToFragments(o, LEVEL_LIST)...]
processObjects rightObjs, refExp
processObjects rightObjs, vvar, refExp
<span class="hljs-keyword">else</span></pre></div></div>
</li>
@@ -5259,7 +5263,7 @@ b) <code>Expansion</code>
</div>
<div class="content"><div class='highlight'><pre> processObjects objects, vvarText
<div class="content"><div class='highlight'><pre> processObjects objects, vvar, vvarText
assigns.push vvar <span class="hljs-keyword">unless</span> top <span class="hljs-keyword">or</span> @subpattern
fragments = @joinFragmentArrays assigns, <span class="hljs-string">', '</span>
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments</pre></div></div>

File diff suppressed because one or more lines are too long

View File

@@ -646,7 +646,7 @@ div.CodeMirror-cursor {
<section id="overview">
<p><strong>CoffeeScript is a little language that compiles into JavaScript.</strong> Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.</p>
<p>The golden rule of CoffeeScript is: <em>“Its just JavaScript.”</em> 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, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.</p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.2.0">2.2.0</a></p>
<p><strong>Latest Version:</strong> <a href="https://github.com/jashkenas/coffeescript/tarball/2.2.1">2.2.1</a></p>
<blockquote class="uneditable-code-block"><pre><code class="language-bash"><span class="comment"># Install locally for a project:</span>
npm install --save-dev coffeescript
@@ -4790,7 +4790,7 @@ The CoffeeScript logo is available in SVG for use in presentations.</li>
</section>
<section id="annotated-source">
<h2>Annotated Source</h2>
<p>You can browse the CoffeeScript 2.2.0 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
<p>You can browse the CoffeeScript 2.2.1 source in readable, annotated form <a href="annotated-source/">here</a>. You can also jump directly to a particular source file:</p>
<ul>
<li><a href="annotated-source/grammar.html">Grammar Rules — src/grammar</a></li>
<li><a href="annotated-source/lexer.html">Lexing Tokens — src/lexer</a></li>
@@ -5467,6 +5467,14 @@ x = <span class="number">2</span> + <span class="number">2</span>
</section>
<section id="changelog">
<h2>Changelog</h2>
<div class="anchor" id="2.2.1"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.1.0...2.2.1">2.2.1</a>
<span class="timestamp"> &mdash; <time datetime="2018-02-06">February 6, 2018</time></span>
</h2><ul>
<li>Bugfix for regression in 2.2.0 involving an error thrown by the compiler in certain cases when using destructuring with a splat or expansion in an array.</li>
<li>Bugfix for regression in 2.2.0 where in certain cases a range iterator variable was declared in the global scope.</li>
</ul>
<div class="anchor" id="2.2.0"></div>
<h2 class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/2.1.1...2.2.0">2.2.0</a>

View File

@@ -1573,6 +1573,46 @@ test "#4673: complex destructured object spread variables", ->
{{g}...} = g: 1
eq g, 1
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
arr = ['a', 'b', 'c', 'd']
f1 = (list) ->
[first, ..., last] = list
f2 = (list) ->
[first..., last] = list
f3 = (list) ->
([first, ...] = list); first
f4 = (list) ->
([first, ...rest] = list); rest
arrayEq f1(arr), arr
arrayEq f2(arr), arr
arrayEq f3(arr), 'a'
arrayEq f4(arr), ['b', 'c', 'd']
foo = (list) ->
ret =
if list?.length > 0
[first, ..., last] = list
[first, last]
else
[]
arrayEq foo(arr), ['a', 'd']
bar = (list) ->
ret =
if list?.length > 0
[first, ...rest] = list
[first, rest]
else
[]
arrayEq bar(arr), ['a', ['b', 'c', 'd']]
</script>
<script type="text/x-coffeescript" class="test" id="async">
# Functions that contain the `await` keyword will compile into async functions,
@@ -16173,6 +16213,13 @@ test "#2047: from, to and step as variables", ->
r = (x for x in [b..a] by step)
arrayEq r, []
test "#4884: Range not declaring var for the 'i'", ->
'use strict'
[0..21].forEach (idx) ->
idx + 1
eq global.i, undefined
</script>
<script type="text/x-coffeescript" class="test" id="regexps">
# Regular Expression Literals

View File

@@ -1,5 +1,11 @@
## Changelog
```
releaseHeader('2018-02-06', '2.2.1', '2.1.0')
```
* Bugfix for regression in 2.2.0 involving an error thrown by the compiler in certain cases when using destructuring with a splat or expansion in an array.
* Bugfix for regression in 2.2.0 where in certain cases a range iterator variable was declared in the global scope.
```
releaseHeader('2018-02-01', '2.2.0', '2.1.1')
```

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// This **Browser** compatibility layer extends core CoffeeScript functions
// to make things work smoothly when compiling code directly in the browser.

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
// ([Rake](http://rake.rubyforge.org/), [Jake](https://github.com/280north/jake))

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// CoffeeScript can be used both on the server, as a command-line compiler based
// on Node.js/V8, or to run CoffeeScript directly in the browser. This module

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison)
// from this grammar file. Jison is a bottom-up parser generator, similar in

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// This file contains the common helper functions that we'd like to share among
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// Node.js Implementation
var CoffeeScript, ext, fs, helpers, i, len, path, ref, universalCompile, vm,

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
// matches against the beginning of the source code. When a match is found,

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// `nodes.coffee` contains all of the node classes for the syntax tree. Most
// nodes are created as the result of actions in the [grammar](grammar.html),
@@ -2043,7 +2043,7 @@
idx = del(o, 'index');
idxName = del(o, 'name');
namedIndex = idxName && idxName !== idx;
varPart = `${idx} = ${this.fromC}`;
varPart = known && !namedIndex ? `var ${idx} = ${this.fromC}` : `${idx} = ${this.fromC}`;
if (this.toC !== this.toVar) {
varPart += `, ${this.toC}`;
}
@@ -3575,8 +3575,8 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
// Sort 'splatsAndExpans' so we can show error at first disallowed token.
objects[splatsAndExpans.sort()[1]].error("multiple splats/expansions are disallowed in an assignment");
}
isSplat = splats.length;
isExpans = expans.length;
isSplat = (splats != null ? splats.length : void 0) > 0;
isExpans = (expans != null ? expans.length : void 0) > 0;
isObject = this.variable.isObject();
isArray = this.variable.isArray();
vvar = value.compileToFragments(o, LEVEL_LIST);
@@ -3648,7 +3648,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
};
// "Complex" `objects` are processed in a loop.
// Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
loopObjects = (objs, vvarTxt) => {
loopObjects = (objs, vvar, vvarTxt) => {
var acc, idx, j, len1, message, objSpreads, results, vval;
objSpreads = hasObjSpreads(objs);
results = [];
@@ -3707,7 +3707,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
return results;
};
// "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
assignObjects = (objs, vvarTxt) => {
assignObjects = (objs, vvar, vvarTxt) => {
var vval;
vvar = new Value(new Arr(objs, true));
vval = vvarTxt instanceof Value ? vvarTxt : new Value(new Literal(vvarTxt));
@@ -3716,11 +3716,11 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
subpattern: true
}).compileToFragments(o, LEVEL_LIST));
};
processObjects = function(objs, vvarTxt) {
processObjects = function(objs, vvar, vvarTxt) {
if (complexObjects(objs)) {
return loopObjects(objs, vvarTxt);
return loopObjects(objs, vvar, vvarTxt);
} else {
return assignObjects(objs, vvarTxt);
return assignObjects(objs, vvar, vvarTxt);
}
};
// In case there is `Splat` or `Expansion` in `objects`,
@@ -3739,7 +3739,7 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
leftObjs = objects.slice(0, expIdx + (isSplat ? 1 : 0));
rightObjs = objects.slice(expIdx + 1);
if (leftObjs.length !== 0) {
processObjects(leftObjs, vvarText);
processObjects(leftObjs, vvar, vvarText);
}
if (rightObjs.length !== 0) {
// Slice or splice `objects`.
@@ -3756,11 +3756,11 @@ this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `
refExp = o.scope.freeVariable('ref');
assigns.push([this.makeCode(refExp + ' = '), ...restVar.compileToFragments(o, LEVEL_LIST)]);
}
processObjects(rightObjs, refExp);
processObjects(rightObjs, vvar, refExp);
}
} else {
// There is no `Splat` or `Expansion` in `objects`.
processObjects(objects, vvarText);
processObjects(objects, vvar, vvarText);
}
if (!(top || this.subpattern)) {
assigns.push(vvar);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
splice = [].splice;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, getRootModule, helpers, i, len, loadFile, path, ref;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
// and shorthand syntax. This can greatly complicate a grammar and bloat

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// 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

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 2.2.0
// Generated by CoffeeScript 2.2.1
(function() {
// Source maps allow JavaScript runtimes to match running JavaScript back to
// the original source code that corresponds to it. This can be minified

View File

@@ -8,7 +8,7 @@
"compiler"
],
"author": "Jeremy Ashkenas",
"version": "2.2.0",
"version": "2.2.1",
"license": "MIT",
"engines": {
"node": ">=6"

View File

@@ -1353,7 +1353,11 @@ exports.Range = class Range extends Base
idx = del o, 'index'
idxName = del o, 'name'
namedIndex = idxName and idxName isnt idx
varPart = "#{idx} = #{@fromC}"
varPart =
if known and not namedIndex
"var #{idx} = #{@fromC}"
else
"#{idx} = #{@fromC}"
varPart += ", #{@toC}" if @toC isnt @toVar
varPart += ", #{@step}" if @step isnt @stepVar
[lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"]
@@ -2408,8 +2412,8 @@ exports.Assign = class Assign extends Base
# Sort 'splatsAndExpans' so we can show error at first disallowed token.
objects[splatsAndExpans.sort()[1]].error "multiple splats/expansions are disallowed in an assignment"
isSplat = splats.length
isExpans = expans.length
isSplat = splats?.length > 0
isExpans = expans?.length > 0
isObject = @variable.isObject()
isArray = @variable.isArray()
@@ -2458,7 +2462,7 @@ exports.Assign = class Assign extends Base
# "Complex" `objects` are processed in a loop.
# Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
loopObjects = (objs, vvarTxt) =>
loopObjects = (objs, vvar, vvarTxt) =>
objSpreads = hasObjSpreads objs
for obj, i in objs
# `Elision` can be skipped.
@@ -2488,16 +2492,16 @@ exports.Assign = class Assign extends Base
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
# "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
assignObjects = (objs, vvarTxt) =>
assignObjects = (objs, vvar, vvarTxt) =>
vvar = new Value new Arr(objs, yes)
vval = if vvarTxt instanceof Value then vvarTxt else new Value new Literal(vvarTxt)
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
processObjects = (objs, vvarTxt) ->
processObjects = (objs, vvar, vvarTxt) ->
if complexObjects objs
loopObjects objs, vvarTxt
loopObjects objs, vvar, vvarTxt
else
assignObjects objs, vvarTxt
assignObjects objs, vvar, vvarTxt
# In case there is `Splat` or `Expansion` in `objects`,
# we can split array in two simple subarrays.
@@ -2514,7 +2518,7 @@ exports.Assign = class Assign extends Base
expIdx = splatsAndExpans[0]
leftObjs = objects.slice 0, expIdx + (if isSplat then 1 else 0)
rightObjs = objects.slice expIdx + 1
processObjects leftObjs, vvarText if leftObjs.length isnt 0
processObjects leftObjs, vvar, vvarText if leftObjs.length isnt 0
if rightObjs.length isnt 0
# Slice or splice `objects`.
refExp = switch
@@ -2524,10 +2528,10 @@ exports.Assign = class Assign extends Base
restVar = refExp
refExp = o.scope.freeVariable 'ref'
assigns.push [@makeCode(refExp + ' = '), restVar.compileToFragments(o, LEVEL_LIST)...]
processObjects rightObjs, refExp
processObjects rightObjs, vvar, refExp
else
# There is no `Splat` or `Expansion` in `objects`.
processObjects objects, vvarText
processObjects objects, vvar, vvarText
assigns.push vvar unless top or @subpattern
fragments = @joinFragmentArrays assigns, ', '
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments

View File

@@ -945,3 +945,43 @@ test "#4673: complex destructured object spread variables", ->
{{g}...} = g: 1
eq g, 1
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
arr = ['a', 'b', 'c', 'd']
f1 = (list) ->
[first, ..., last] = list
f2 = (list) ->
[first..., last] = list
f3 = (list) ->
([first, ...] = list); first
f4 = (list) ->
([first, ...rest] = list); rest
arrayEq f1(arr), arr
arrayEq f2(arr), arr
arrayEq f3(arr), 'a'
arrayEq f4(arr), ['b', 'c', 'd']
foo = (list) ->
ret =
if list?.length > 0
[first, ..., last] = list
[first, last]
else
[]
arrayEq foo(arr), ['a', 'd']
bar = (list) ->
ret =
if list?.length > 0
[first, ...rest] = list
[first, rest]
else
[]
arrayEq bar(arr), ['a', ['b', 'c', 'd']]

View File

@@ -195,3 +195,10 @@ test "#2047: from, to and step as variables", ->
step = 0
r = (x for x in [b..a] by step)
arrayEq r, []
test "#4884: Range not declaring var for the 'i'", ->
'use strict'
[0..21].forEach (idx) ->
idx + 1
eq global.i, undefined