mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 08:47:55 -05:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a73f66bc11 | ||
|
|
ba094126e2 | ||
|
|
794f65fbd7 | ||
|
|
0490eb9a3a | ||
|
|
9e80f6fa67 | ||
|
|
fc5ab1afa3 | ||
|
|
0aa77f157a | ||
|
|
1849f0db76 | ||
|
|
d86597dbad | ||
|
|
bf91781888 | ||
|
|
dcd6de9a77 | ||
|
|
70b510bcb7 | ||
|
|
84d596d534 | ||
|
|
c804087ec9 | ||
|
|
74bd537d6c | ||
|
|
0217ed5505 | ||
|
|
e53307b46b | ||
|
|
c8c8c167d1 | ||
|
|
c1283ead45 | ||
|
|
3ade25a32c | ||
|
|
7ea3ea92f3 | ||
|
|
a70f1a082e | ||
|
|
2ccbb6b91a | ||
|
|
e348026073 | ||
|
|
7c6f3788ca |
2
Cakefile
2
Cakefile
@@ -332,7 +332,7 @@ task 'doc:test:watch', 'watch and continually rebuild the browser-based tests',
|
||||
|
||||
buildAnnotatedSource = (watch = no) ->
|
||||
do generateAnnotatedSource = ->
|
||||
exec "node_modules/docco/bin/docco src/*.*coffee --output docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
exec "cd src && ../node_modules/docco/bin/docco *.*coffee --output ../docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
log 'generated', green, "annotated source in docs/v#{majorVersion}/annotated-source/"
|
||||
|
||||
if watch
|
||||
|
||||
7
bin/cake
7
bin/cake
@@ -1,5 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
try {
|
||||
new Function('var {a} = {a: 1}')();
|
||||
} catch (error) {
|
||||
console.error('Your JavaScript runtime does not support some features used by the cake command. Please use Node 6 or later.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
try {
|
||||
new Function('var {a} = {a: 1}')();
|
||||
} catch (error) {
|
||||
console.error('Your JavaScript runtime does not support some features used by the coffee command. Please use Node 6 or later.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
@@ -357,6 +357,7 @@ grammar.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Line: [
|
||||
o <span class="hljs-string">'Expression'</span>
|
||||
o <span class="hljs-string">'ExpressionLine'</span>
|
||||
o <span class="hljs-string">'Statement'</span>
|
||||
o <span class="hljs-string">'FuncDirective'</span>
|
||||
]
|
||||
@@ -415,6 +416,27 @@ them somewhat circular.</p>
|
||||
o <span class="hljs-string">'Class'</span>
|
||||
o <span class="hljs-string">'Throw'</span>
|
||||
o <span class="hljs-string">'Yield'</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Expressions which are written in single line and would otherwise require being
|
||||
wrapped in braces: E.g <code>a = b if do -> f a is 1</code>, <code>if f (a) -> a*2 then ...</code>,
|
||||
<code>for x in do (obj) -> f obj when x > 8 then f x</code></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ExpressionLine: [
|
||||
o <span class="hljs-string">'CodeLine'</span>
|
||||
o <span class="hljs-string">'IfLine'</span>
|
||||
o <span class="hljs-string">'OperationLine'</span>
|
||||
]
|
||||
|
||||
Yield: [
|
||||
@@ -426,11 +448,11 @@ them somewhat circular.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-17">
|
||||
<li id="section-18">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>An indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
|
||||
will convert some postfix forms into blocks for us, by adjusting the
|
||||
@@ -455,11 +477,11 @@ token stream.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-18">
|
||||
<li id="section-19">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
|
||||
they can also serve as keys in object literals.</p>
|
||||
@@ -484,11 +506,11 @@ they can also serve as keys in object literals.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-19">
|
||||
<li id="section-20">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>All of our immediate values. Generally these can be passed straight
|
||||
through and printed to JavaScript.</p>
|
||||
@@ -509,11 +531,11 @@ through and printed to JavaScript.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-20">
|
||||
<li id="section-21">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>Assignment of a variable, property, or index to a value.</p>
|
||||
|
||||
@@ -528,11 +550,11 @@ through and printed to JavaScript.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-21">
|
||||
<li id="section-22">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>Assignment when it happens within an object literal. The difference from
|
||||
the ordinary <strong>Assign</strong> is that these allow numbers and strings as keys.</p>
|
||||
@@ -569,11 +591,11 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-22">
|
||||
<li id="section-23">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Object literal spread properties.</p>
|
||||
|
||||
@@ -610,11 +632,11 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-23">
|
||||
<li id="section-24">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>A return statement from a function body.</p>
|
||||
|
||||
@@ -639,11 +661,11 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-24">
|
||||
<li id="section-25">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
</div>
|
||||
<p>The <strong>Code</strong> node is the function literal. It’s defined by an indented block
|
||||
of <strong>Block</strong> preceded by a function arrow, with an optional parameter list.</p>
|
||||
@@ -658,11 +680,30 @@ of <strong>Block</strong> preceded by a function arrow, with an optional paramet
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-25">
|
||||
<li id="section-26">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-25">¶</a>
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>The Codeline is the <strong>Code</strong> node with <strong>Line</strong> instead of indented <strong>Block</strong>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> CodeLine: [
|
||||
o <span class="hljs-string">'PARAM_START ParamList PARAM_END FuncGlyph Line'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Code $<span class="hljs-number">2</span>, LOC(<span class="hljs-number">5</span>)(Block.wrap [$<span class="hljs-number">5</span>]), $<span class="hljs-number">4</span>,
|
||||
LOC(<span class="hljs-number">1</span>)(<span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>)
|
||||
o <span class="hljs-string">'FuncGlyph Line'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Code [], LOC(<span class="hljs-number">2</span>)(Block.wrap [$<span class="hljs-number">2</span>]), $<span class="hljs-number">1</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-27">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>CoffeeScript has two different symbols for functions. <code>-></code> is for ordinary
|
||||
functions, and <code>=></code> is for functions bound to the current value of <em>this</em>.</p>
|
||||
@@ -677,11 +718,11 @@ functions, and <code>=></code> is for functions bound to the current value of
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-26">
|
||||
<li id="section-28">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>An optional, trailing comma.</p>
|
||||
|
||||
@@ -695,11 +736,11 @@ functions, and <code>=></code> is for functions bound to the current value of
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-27">
|
||||
<li id="section-29">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>The list of parameters that a function accepts can be of any length.</p>
|
||||
|
||||
@@ -716,11 +757,11 @@ functions, and <code>=></code> is for functions bound to the current value of
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-28">
|
||||
<li id="section-30">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>A single parameter in a function definition can be ordinary, or a splat
|
||||
that hoovers up the remaining arguments.</p>
|
||||
@@ -738,11 +779,11 @@ that hoovers up the remaining arguments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-29">
|
||||
<li id="section-31">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>Function Parameters</p>
|
||||
|
||||
@@ -758,11 +799,11 @@ that hoovers up the remaining arguments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-30">
|
||||
<li id="section-32">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
<a class="pilcrow" href="#section-32">¶</a>
|
||||
</div>
|
||||
<p>A splat that occurs outside of a parameter list.</p>
|
||||
|
||||
@@ -776,11 +817,11 @@ that hoovers up the remaining arguments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-31">
|
||||
<li id="section-33">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
<a class="pilcrow" href="#section-33">¶</a>
|
||||
</div>
|
||||
<p>Variables and properties that can be assigned to.</p>
|
||||
|
||||
@@ -796,11 +837,11 @@ that hoovers up the remaining arguments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-32">
|
||||
<li id="section-34">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-32">¶</a>
|
||||
<a class="pilcrow" href="#section-34">¶</a>
|
||||
</div>
|
||||
<p>Everything that can be assigned to.</p>
|
||||
|
||||
@@ -815,11 +856,11 @@ that hoovers up the remaining arguments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-33">
|
||||
<li id="section-35">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-33">¶</a>
|
||||
<a class="pilcrow" href="#section-35">¶</a>
|
||||
</div>
|
||||
<p>The types of things that can be treated as values – assigned to, invoked
|
||||
as functions, indexed into, named as a class, etc.</p>
|
||||
@@ -839,11 +880,11 @@ as functions, indexed into, named as a class, etc.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-34">
|
||||
<li id="section-36">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-34">¶</a>
|
||||
<a class="pilcrow" href="#section-36">¶</a>
|
||||
</div>
|
||||
<p>A <code>super</code>-based expression that can be used as a value.</p>
|
||||
|
||||
@@ -857,11 +898,11 @@ as functions, indexed into, named as a class, etc.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-35">
|
||||
<li id="section-37">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-35">¶</a>
|
||||
<a class="pilcrow" href="#section-37">¶</a>
|
||||
</div>
|
||||
<p>The general group of accessors into an object, by property, by prototype
|
||||
or by array index or slice.</p>
|
||||
@@ -880,11 +921,11 @@ or by array index or slice.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-36">
|
||||
<li id="section-38">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-36">¶</a>
|
||||
<a class="pilcrow" href="#section-38">¶</a>
|
||||
</div>
|
||||
<p>Indexing into an object or array using bracket notation.</p>
|
||||
|
||||
@@ -903,11 +944,11 @@ or by array index or slice.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-37">
|
||||
<li id="section-39">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-37">¶</a>
|
||||
<a class="pilcrow" href="#section-39">¶</a>
|
||||
</div>
|
||||
<p>In CoffeeScript, an object literal is simply a list of assignments.</p>
|
||||
|
||||
@@ -920,11 +961,11 @@ or by array index or slice.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-38">
|
||||
<li id="section-40">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-38">¶</a>
|
||||
<a class="pilcrow" href="#section-40">¶</a>
|
||||
</div>
|
||||
<p>Assignment of properties within an object literal can be separated by
|
||||
comma, as in JavaScript, or simply by newline.</p>
|
||||
@@ -942,11 +983,11 @@ comma, as in JavaScript, or simply by newline.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-39">
|
||||
<li id="section-41">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-39">¶</a>
|
||||
<a class="pilcrow" href="#section-41">¶</a>
|
||||
</div>
|
||||
<p>Class definitions have optional bodies of prototype property assignments,
|
||||
and optional references to the superclass.</p>
|
||||
@@ -1032,11 +1073,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-40">
|
||||
<li id="section-42">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-40">¶</a>
|
||||
<a class="pilcrow" href="#section-42">¶</a>
|
||||
</div>
|
||||
<p>Ordinary function invocation, or a chained series of calls.</p>
|
||||
|
||||
@@ -1051,11 +1092,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-41">
|
||||
<li id="section-43">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-41">¶</a>
|
||||
<a class="pilcrow" href="#section-43">¶</a>
|
||||
</div>
|
||||
<p>An optional existence check on a function.</p>
|
||||
|
||||
@@ -1069,11 +1110,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-42">
|
||||
<li id="section-44">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-42">¶</a>
|
||||
<a class="pilcrow" href="#section-44">¶</a>
|
||||
</div>
|
||||
<p>The list of arguments to a function call.</p>
|
||||
|
||||
@@ -1087,11 +1128,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-43">
|
||||
<li id="section-45">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-43">¶</a>
|
||||
<a class="pilcrow" href="#section-45">¶</a>
|
||||
</div>
|
||||
<p>A reference to the <em>this</em> current object.</p>
|
||||
|
||||
@@ -1105,11 +1146,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-44">
|
||||
<li id="section-46">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-44">¶</a>
|
||||
<a class="pilcrow" href="#section-46">¶</a>
|
||||
</div>
|
||||
<p>A reference to a property on <em>this</em>.</p>
|
||||
|
||||
@@ -1122,11 +1163,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-45">
|
||||
<li id="section-47">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-45">¶</a>
|
||||
<a class="pilcrow" href="#section-47">¶</a>
|
||||
</div>
|
||||
<p>The array literal.</p>
|
||||
|
||||
@@ -1141,11 +1182,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-46">
|
||||
<li id="section-48">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-46">¶</a>
|
||||
<a class="pilcrow" href="#section-48">¶</a>
|
||||
</div>
|
||||
<p>Inclusive and exclusive range dots.</p>
|
||||
|
||||
@@ -1159,28 +1200,29 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-47">
|
||||
<li id="section-49">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-47">¶</a>
|
||||
<a class="pilcrow" href="#section-49">¶</a>
|
||||
</div>
|
||||
<p>The CoffeeScript range literal.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Range: [
|
||||
o <span class="hljs-string">'[ Expression RangeDots Expression ]'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'[ Expression RangeDots Expression ]'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'[ ExpressionLine RangeDots Expression ]'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">3</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-48">
|
||||
<li id="section-50">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-48">¶</a>
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
</div>
|
||||
<p>Array slice literals.</p>
|
||||
|
||||
@@ -1189,6 +1231,8 @@ and optional references to the superclass.</p>
|
||||
<div class="content"><div class='highlight'><pre> Slice: [
|
||||
o <span class="hljs-string">'Expression RangeDots Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'Expression RangeDots'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">1</span>, <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'ExpressionLine RangeDots Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'ExpressionLine RangeDots'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range $<span class="hljs-number">1</span>, <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'RangeDots Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range <span class="hljs-literal">null</span>, $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
|
||||
o <span class="hljs-string">'RangeDots'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Range <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, $<span class="hljs-number">1</span>
|
||||
]</pre></div></div>
|
||||
@@ -1196,11 +1240,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-49">
|
||||
<li id="section-51">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-49">¶</a>
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
</div>
|
||||
<p>The <strong>ArgList</strong> is the list of objects passed into a function call
|
||||
(i.e. comma-separated expressions). Newlines work as well.</p>
|
||||
@@ -1218,11 +1262,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<li id="section-52">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
</div>
|
||||
<p>Valid arguments are Blocks or Splats.</p>
|
||||
|
||||
@@ -1230,6 +1274,7 @@ and optional references to the superclass.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Arg: [
|
||||
o <span class="hljs-string">'Expression'</span>
|
||||
o <span class="hljs-string">'ExpressionLine'</span>
|
||||
o <span class="hljs-string">'Splat'</span>
|
||||
o <span class="hljs-string">'...'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Expansion
|
||||
]</pre></div></div>
|
||||
@@ -1237,11 +1282,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<li id="section-53">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
</div>
|
||||
<p>The <strong>ArgElisionList</strong> is the list of objects, contents of an array literal
|
||||
(i.e. comma-separated expressions and elisions). Newlines work as well.</p>
|
||||
@@ -1278,11 +1323,11 @@ and optional references to the superclass.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<li id="section-54">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
</div>
|
||||
<p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
|
||||
@@ -1292,17 +1337,19 @@ having the newlines wouldn’t make sense.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> SimpleArgs: [
|
||||
o <span class="hljs-string">'Expression'</span>
|
||||
o <span class="hljs-string">'ExpressionLine'</span>
|
||||
o <span class="hljs-string">'SimpleArgs , Expression'</span>, <span class="hljs-function">-></span> [].concat $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'SimpleArgs , ExpressionLine'</span>, <span class="hljs-function">-></span> [].concat $<span class="hljs-number">1</span>, $<span class="hljs-number">3</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<li id="section-55">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
</div>
|
||||
<p>The variants of <em>try/catch/finally</em> exception handling blocks.</p>
|
||||
|
||||
@@ -1318,11 +1365,11 @@ having the newlines wouldn’t make sense.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-54">
|
||||
<li id="section-56">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
</div>
|
||||
<p>A catch clause names its error and runs a block of code.</p>
|
||||
|
||||
@@ -1337,11 +1384,11 @@ having the newlines wouldn’t make sense.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-55">
|
||||
<li id="section-57">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
</div>
|
||||
<p>Throw an exception object.</p>
|
||||
|
||||
@@ -1355,11 +1402,11 @@ having the newlines wouldn’t make sense.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-56">
|
||||
<li id="section-58">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
|
||||
not an <strong>Expression</strong>, so if you need to use an expression in a place
|
||||
@@ -1376,31 +1423,40 @@ the trick.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-57">
|
||||
<li id="section-59">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
</div>
|
||||
<p>The condition portion of a while loop.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> WhileSource: [
|
||||
<div class="content"><div class='highlight'><pre> WhileLineSource: [
|
||||
o <span class="hljs-string">'WHILE ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'WHILE ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'UNTIL ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, invert: <span class="hljs-literal">true</span>
|
||||
o <span class="hljs-string">'UNTIL ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, invert: <span class="hljs-literal">true</span>, guard: $<span class="hljs-number">4</span>
|
||||
]
|
||||
|
||||
WhileSource: [
|
||||
o <span class="hljs-string">'WHILE Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'WHILE Expression WHEN Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'WHILE ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'UNTIL Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, invert: <span class="hljs-literal">true</span>
|
||||
o <span class="hljs-string">'UNTIL Expression WHEN Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, invert: <span class="hljs-literal">true</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'UNTIL ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> While $<span class="hljs-number">2</span>, invert: <span class="hljs-literal">true</span>, guard: $<span class="hljs-number">4</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<li id="section-60">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
</div>
|
||||
<p>The while loop can either be normal, with a block of expressions to execute,
|
||||
or postfix, with a single expression. There is no do..while.</p>
|
||||
@@ -1409,6 +1465,7 @@ or postfix, with a single expression. There is no do..while.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> While: [
|
||||
o <span class="hljs-string">'WhileSource Block'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>addBody $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'WhileLineSource Block'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>addBody $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'Statement WhileSource'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">2.</span>addBody LOC(<span class="hljs-number">1</span>) Block.wrap([$<span class="hljs-number">1</span>])
|
||||
o <span class="hljs-string">'Expression WhileSource'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">2.</span>addBody LOC(<span class="hljs-number">1</span>) Block.wrap([$<span class="hljs-number">1</span>])
|
||||
o <span class="hljs-string">'Loop'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1</span>
|
||||
@@ -1422,11 +1479,11 @@ or postfix, with a single expression. There is no do..while.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<li id="section-61">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
</div>
|
||||
<p>Array, object, and range comprehensions, at the most generic level.
|
||||
Comprehensions can either be normal, with a block of expressions to execute,
|
||||
@@ -1438,6 +1495,7 @@ or postfix, with a single expression.</p>
|
||||
o <span class="hljs-string">'Statement ForBody'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> For $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'Expression ForBody'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> For $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'ForBody Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> For $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
|
||||
o <span class="hljs-string">'ForLineBody Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> For $<span class="hljs-number">2</span>, $<span class="hljs-number">1</span>
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
@@ -1446,6 +1504,11 @@ or postfix, with a single expression.</p>
|
||||
o <span class="hljs-string">'ForStart ForSource'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">2.</span>own = $<span class="hljs-number">1.</span>own; $<span class="hljs-number">2.</span>ownTag = $<span class="hljs-number">1.</span>ownTag; $<span class="hljs-number">2.</span>name = $<span class="hljs-number">1</span>[<span class="hljs-number">0</span>]; $<span class="hljs-number">2.</span>index = $<span class="hljs-number">1</span>[<span class="hljs-number">1</span>]; $<span class="hljs-number">2</span>
|
||||
]
|
||||
|
||||
ForLineBody: [
|
||||
o <span class="hljs-string">'FOR Range BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: (LOC(<span class="hljs-number">2</span>) <span class="hljs-keyword">new</span> Value($<span class="hljs-number">2</span>)), step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'ForStart ForLineSource'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">2.</span>own = $<span class="hljs-number">1.</span>own; $<span class="hljs-number">2.</span>ownTag = $<span class="hljs-number">1.</span>ownTag; $<span class="hljs-number">2.</span>name = $<span class="hljs-number">1</span>[<span class="hljs-number">0</span>]; $<span class="hljs-number">2.</span>index = $<span class="hljs-number">1</span>[<span class="hljs-number">1</span>]; $<span class="hljs-number">2</span>
|
||||
]
|
||||
|
||||
ForStart: [
|
||||
o <span class="hljs-string">'FOR ForVariables'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'FOR OWN ForVariables'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">3.</span>own = <span class="hljs-literal">yes</span>; $<span class="hljs-number">3.</span>ownTag = (LOC(<span class="hljs-number">2</span>) <span class="hljs-keyword">new</span> Literal($<span class="hljs-number">2</span>)); $<span class="hljs-number">3</span>
|
||||
@@ -1454,11 +1517,11 @@ or postfix, with a single expression.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<li id="section-62">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
</div>
|
||||
<p>An array of all accepted values for a variable inside the loop.
|
||||
This enables support for pattern matching.</p>
|
||||
@@ -1475,11 +1538,11 @@ This enables support for pattern matching.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-61">
|
||||
<li id="section-63">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
</div>
|
||||
<p>An array or range comprehension has variables for the current element
|
||||
and (optional) reference to the current index. Or, <em>key, value</em>, in the case
|
||||
@@ -1495,11 +1558,11 @@ of object comprehensions.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-62">
|
||||
<li id="section-64">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
</div>
|
||||
<p>The source of a comprehension is an array or object with an optional guard
|
||||
clause. If it’s an array comprehension, you can also choose to step through
|
||||
@@ -1508,22 +1571,56 @@ in fixed-size increments.</p>
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ForSource: [
|
||||
o <span class="hljs-string">'FORIN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'FOROF Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FOROF Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN Expression BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORFROM Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORFROM Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'FOROF Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FOROF Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FOROF ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN Expression BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN Expression BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN ExpressionLine BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN ExpressionLine BY Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORFROM Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORFROM Expression WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORFROM ExpressionLine WHEN Expression'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, from: <span class="hljs-literal">yes</span>
|
||||
]
|
||||
|
||||
ForLineSource: [
|
||||
o <span class="hljs-string">'FORIN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'FOROF ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FOROF Expression WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FOROF ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, object: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN Expression BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN Expression BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression WHEN ExpressionLine BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, step: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY Expression WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY Expression WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN Expression BY ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, step: $<span class="hljs-number">4</span>, guard: $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'FORFROM ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORFROM Expression WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, from: <span class="hljs-literal">yes</span>
|
||||
o <span class="hljs-string">'FORFROM ExpressionLine WHEN ExpressionLine'</span>, <span class="hljs-function">-></span> source: $<span class="hljs-number">2</span>, guard: $<span class="hljs-number">4</span>, from: <span class="hljs-literal">yes</span>
|
||||
]
|
||||
|
||||
Switch: [
|
||||
o <span class="hljs-string">'SWITCH Expression INDENT Whens OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'SWITCH Expression INDENT Whens ELSE Block OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'SWITCH INDENT Whens OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch <span class="hljs-literal">null</span>, $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'SWITCH INDENT Whens ELSE Block OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch <span class="hljs-literal">null</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">5</span>
|
||||
o <span class="hljs-string">'SWITCH Expression INDENT Whens OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'SWITCH ExpressionLine INDENT Whens OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>
|
||||
o <span class="hljs-string">'SWITCH Expression INDENT Whens ELSE Block OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch $<span class="hljs-number">2</span>, $<span class="hljs-number">4</span>, $<span class="hljs-number">6</span>
|
||||
o <span class="hljs-string">'SWITCH INDENT Whens OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch <span class="hljs-literal">null</span>, $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'SWITCH INDENT Whens ELSE Block OUTDENT'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Switch <span class="hljs-literal">null</span>, $<span class="hljs-number">3</span>, $<span class="hljs-number">5</span>
|
||||
]
|
||||
|
||||
Whens: [
|
||||
@@ -1534,11 +1631,11 @@ in fixed-size increments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-63">
|
||||
<li id="section-65">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
</div>
|
||||
<p>An individual <strong>When</strong> clause, with action.</p>
|
||||
|
||||
@@ -1552,11 +1649,11 @@ in fixed-size increments.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-64">
|
||||
<li id="section-66">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
</div>
|
||||
<p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
if-related rules are broken up along these lines in order to avoid
|
||||
@@ -1572,11 +1669,11 @@ ambiguity.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-65">
|
||||
<li id="section-67">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
</div>
|
||||
<p>The full complement of <em>if</em> expressions, including postfix one-liner
|
||||
<em>if</em> and <em>unless</em>.</p>
|
||||
@@ -1588,16 +1685,28 @@ ambiguity.</p>
|
||||
o <span class="hljs-string">'IfBlock ELSE Block'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>addElse $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'Statement POST_IF Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> If $<span class="hljs-number">3</span>, LOC(<span class="hljs-number">1</span>)(Block.wrap [$<span class="hljs-number">1</span>]), type: $<span class="hljs-number">2</span>, statement: <span class="hljs-literal">true</span>
|
||||
o <span class="hljs-string">'Expression POST_IF Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> If $<span class="hljs-number">3</span>, LOC(<span class="hljs-number">1</span>)(Block.wrap [$<span class="hljs-number">1</span>]), type: $<span class="hljs-number">2</span>, statement: <span class="hljs-literal">true</span>
|
||||
]
|
||||
|
||||
IfBlockLine: [
|
||||
o <span class="hljs-string">'IF ExpressionLine Block'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> If $<span class="hljs-number">2</span>, $<span class="hljs-number">3</span>, type: $<span class="hljs-number">1</span>
|
||||
o <span class="hljs-string">'IfBlockLine ELSE IF ExpressionLine Block'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>addElse LOC(<span class="hljs-number">3</span>,<span class="hljs-number">5</span>) <span class="hljs-keyword">new</span> If $<span class="hljs-number">4</span>, $<span class="hljs-number">5</span>, type: $<span class="hljs-number">3</span>
|
||||
]
|
||||
|
||||
IfLine: [
|
||||
o <span class="hljs-string">'IfBlockLine'</span>
|
||||
o <span class="hljs-string">'IfBlockLine ELSE Block'</span>, <span class="hljs-function">-></span> $<span class="hljs-number">1.</span>addElse $<span class="hljs-number">3</span>
|
||||
o <span class="hljs-string">'Statement POST_IF ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> If $<span class="hljs-number">3</span>, LOC(<span class="hljs-number">1</span>)(Block.wrap [$<span class="hljs-number">1</span>]), type: $<span class="hljs-number">2</span>, statement: <span class="hljs-literal">true</span>
|
||||
o <span class="hljs-string">'Expression POST_IF ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> If $<span class="hljs-number">3</span>, LOC(<span class="hljs-number">1</span>)(Block.wrap [$<span class="hljs-number">1</span>]), type: $<span class="hljs-number">2</span>, statement: <span class="hljs-literal">true</span>
|
||||
]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-66">
|
||||
<li id="section-68">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
</div>
|
||||
<p>Arithmetic and logical operators, working on one or more operands.
|
||||
Here they are grouped by order of precedence. The actual precedence rules
|
||||
@@ -1608,7 +1717,11 @@ rules are necessary.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> Operation: [
|
||||
<div class="content"><div class='highlight'><pre> OperationLine: [
|
||||
o <span class="hljs-string">'UNARY ExpressionLine'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>
|
||||
]
|
||||
|
||||
Operation: [
|
||||
o <span class="hljs-string">'UNARY Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'UNARY_MATH Expression'</span>, <span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
|
||||
o <span class="hljs-string">'- Expression'</span>, (<span class="hljs-function">-></span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'-'</span>, $<span class="hljs-number">2</span>), prec: <span class="hljs-string">'UNARY_MATH'</span>
|
||||
@@ -1624,11 +1737,11 @@ rules are necessary.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-67">
|
||||
<li id="section-69">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
</div>
|
||||
<p><a href="http://coffeescript.org/#existential-operator">The existential operator</a>.</p>
|
||||
|
||||
@@ -1666,11 +1779,11 @@ rules are necessary.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-68">
|
||||
<li id="section-70">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
</div>
|
||||
<h2 id="precedence">Precedence</h2>
|
||||
|
||||
@@ -1679,11 +1792,11 @@ rules are necessary.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-69">
|
||||
<li id="section-71">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
<a class="pilcrow" href="#section-71">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1691,11 +1804,11 @@ rules are necessary.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-70">
|
||||
<li id="section-72">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
<a class="pilcrow" href="#section-72">¶</a>
|
||||
</div>
|
||||
<p>Operators at the top of this list have higher precedence than the ones lower
|
||||
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
@@ -1736,11 +1849,11 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-71">
|
||||
<li id="section-73">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-71">¶</a>
|
||||
<a class="pilcrow" href="#section-73">¶</a>
|
||||
</div>
|
||||
<h2 id="wrapping-up">Wrapping Up</h2>
|
||||
|
||||
@@ -1749,11 +1862,11 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-72">
|
||||
<li id="section-74">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-72">¶</a>
|
||||
<a class="pilcrow" href="#section-74">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1761,11 +1874,11 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-73">
|
||||
<li id="section-75">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-73">¶</a>
|
||||
<a class="pilcrow" href="#section-75">¶</a>
|
||||
</div>
|
||||
<p>Finally, now that we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
|
||||
@@ -1785,11 +1898,11 @@ as “tokens”.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-74">
|
||||
<li id="section-76">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-74">¶</a>
|
||||
<a class="pilcrow" href="#section-76">¶</a>
|
||||
</div>
|
||||
<p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
rules, and the name of the root. Reverse the operators because Jison orders
|
||||
|
||||
@@ -461,13 +461,17 @@ what CoffeeScript would normally interpret as calls to functions named
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'PROPERTY'</span> <span class="hljs-keyword">and</span> prev
|
||||
<span class="hljs-keyword">if</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span> @tokens[@tokens.length - <span class="hljs-number">2</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.'</span>
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call without parentheses"</span>, prev[<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">else</span>
|
||||
<span class="hljs-keyword">if</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens.length > <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> @tokens[@tokens.length - <span class="hljs-number">2</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'.'</span>, <span class="hljs-string">'?.'</span>, <span class="hljs-string">'@'</span>]
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call
|
||||
without parentheses"</span>, prev[<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @tokens.length > <span class="hljs-number">2</span>
|
||||
prevprev = @tokens[@tokens.length - <span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'@'</span>, <span class="hljs-string">'THIS'</span>] <span class="hljs-keyword">and</span> prevprev <span class="hljs-keyword">and</span> prevprev.spaced <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^[gs]et$/</span>.test(prevprev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens[@tokens.length - <span class="hljs-number">3</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.'</span>
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prevprev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a function call without parentheses"</span>, prevprev[<span class="hljs-number">2</span>]
|
||||
<span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'@'</span>, <span class="hljs-string">'THIS'</span>] <span class="hljs-keyword">and</span> prevprev <span class="hljs-keyword">and</span> prevprev.spaced <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-regexp">/^[gs]et$/</span>.test(prevprev[<span class="hljs-number">1</span>]) <span class="hljs-keyword">and</span>
|
||||
@tokens[@tokens.length - <span class="hljs-number">3</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'.'</span>, <span class="hljs-string">'?.'</span>, <span class="hljs-string">'@'</span>]
|
||||
@error <span class="hljs-string">"'<span class="hljs-subst">#{prevprev[<span class="hljs-number">1</span>]}</span>' cannot be used as a keyword, or as a
|
||||
function call without parentheses"</span>, prevprev[<span class="hljs-number">2</span>]
|
||||
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'IDENTIFIER'</span> <span class="hljs-keyword">and</span> id <span class="hljs-keyword">in</span> RESERVED
|
||||
@error <span class="hljs-string">"reserved word '<span class="hljs-subst">#{id}</span>'"</span>, length: id.length
|
||||
@@ -915,7 +919,9 @@ can close multiple indents, so we need to know how far in we happen to be.</p>
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = MULTI_DENT.exec chunk
|
||||
indent = match[<span class="hljs-number">0</span>]
|
||||
|
||||
@seenFor = <span class="hljs-literal">no</span>
|
||||
prev = @prev()
|
||||
backslash = prev? <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'\\'</span>
|
||||
@seenFor = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> backslash <span class="hljs-keyword">and</span> @seenFor
|
||||
@seenImport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @importSpecifierList
|
||||
@seenExport = <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @exportSpecifierList
|
||||
|
||||
@@ -1641,8 +1647,8 @@ of <code>'NEOSTRING'</code>s are converted using <code>fn</code> and tur
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<p>This is an interpolated string, not a CSX tag; and for whatever
|
||||
reason <code>`a${/*test*/}b` </code> is invalid JS. So compile to
|
||||
<code>`a${/*test*/''}b` </code> instead.</p>
|
||||
reason <code>`a${/*test*/}b`</code> is invalid JS. So compile to
|
||||
<code>`a${/*test*/''}b`</code> instead.</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -676,7 +676,21 @@ class declaration or if-conditionals).</p>
|
||||
endImplicitObject()
|
||||
<span class="hljs-keyword">else</span>
|
||||
stack.pop()
|
||||
start = stack.pop()</pre></div></div>
|
||||
start = stack.pop()
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">inControlFlow</span> = =></span>
|
||||
seenFor = @findTagsBackwards(i, [<span class="hljs-string">'FOR'</span>]) <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">'FORIN'</span>, <span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'FORFROM'</span>])
|
||||
controlFlow = seenFor <span class="hljs-keyword">or</span> @findTagsBackwards i, [<span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'LOOP'</span>, <span class="hljs-string">'LEADING_WHEN'</span>]
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> controlFlow
|
||||
isFunc = <span class="hljs-literal">no</span>
|
||||
tagCurrentLine = token[<span class="hljs-number">2</span>].first_line
|
||||
@detectEnd i,
|
||||
<span class="hljs-function"><span class="hljs-params">(token, i)</span> -></span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> LINEBREAKS
|
||||
(token, i) ->
|
||||
[prevTag, ,{first_line}] = tokens[i - <span class="hljs-number">1</span>] || []
|
||||
isFunc = tagCurrentLine <span class="hljs-keyword">is</span> first_line <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>]
|
||||
returnOnNegativeLevel: <span class="hljs-literal">yes</span>
|
||||
isFunc</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -698,7 +712,8 @@ Added support for spread dots on the left side: f …a</p>
|
||||
(nextTag <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">or</span>
|
||||
(nextTag <span class="hljs-keyword">is</span> <span class="hljs-string">'...'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">2</span>) <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @findTagsBackwards(i, [<span class="hljs-string">'INDEX_START'</span>, <span class="hljs-string">'['</span>])) <span class="hljs-keyword">or</span>
|
||||
nextTag <span class="hljs-keyword">in</span> IMPLICIT_UNSPACED_CALL <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> nextToken.spaced <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextToken.newLine)
|
||||
<span class="hljs-keyword">not</span> nextToken.spaced <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextToken.newLine) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> inControlFlow()
|
||||
tag = token[<span class="hljs-number">0</span>] = <span class="hljs-string">'FUNC_EXIST'</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span>
|
||||
startImplicitCall i + <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">return</span> forward(<span class="hljs-number">2</span>)</pre></div></div>
|
||||
@@ -835,7 +850,9 @@ like e.g.:</p>
|
||||
stackItem[<span class="hljs-number">2</span>].sameLine = <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> isImplicitObject stackItem
|
||||
|
||||
newLine = prevTag <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span> <span class="hljs-keyword">or</span> prevToken.newLine
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_END <span class="hljs-keyword">or</span> tag <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span> newLine
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_END <span class="hljs-keyword">or</span>
|
||||
(tag <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span> newLine) <span class="hljs-keyword">or</span>
|
||||
(tag <span class="hljs-keyword">in</span> [<span class="hljs-string">'..'</span>, <span class="hljs-string">'...'</span>] <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">"INDEX_START"</span>]))
|
||||
<span class="hljs-keyword">while</span> inImplicit()
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()</pre></div></div>
|
||||
|
||||
@@ -852,7 +869,8 @@ like e.g.:</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> inImplicitCall() <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">','</span>
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> inImplicitCall() <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">','</span> <span class="hljs-keyword">or</span>
|
||||
(prevTag <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> nextTag?)
|
||||
endImplicitCall()</pre></div></div>
|
||||
|
||||
</li>
|
||||
@@ -1245,20 +1263,101 @@ blocks are added.</p>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> normalizeLines: <span class="hljs-function">-></span>
|
||||
starter = indent = outdent = <span class="hljs-literal">null</span>
|
||||
leading_switch_when = <span class="hljs-literal">null</span>
|
||||
leading_if_then = <span class="hljs-literal">null</span></pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
</div>
|
||||
<p>Count <code>THEN</code> tags</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> ifThens = []
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">condition</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
token[<span class="hljs-number">1</span>] <span class="hljs-keyword">isnt</span> <span class="hljs-string">';'</span> <span class="hljs-keyword">and</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> SINGLE_CLOSERS <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> EXPRESSION_CLOSE) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">isnt</span> <span class="hljs-string">'THEN'</span>) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span>
|
||||
(starter <span class="hljs-keyword">isnt</span> <span class="hljs-string">'THEN'</span> <span class="hljs-keyword">or</span> (leading_if_then <span class="hljs-keyword">or</span> leading_switch_when))) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'CATCH'</span>, <span class="hljs-string">'FINALLY'</span>] <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>]) <span class="hljs-keyword">or</span>
|
||||
token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALL_CLOSERS <span class="hljs-keyword">and</span>
|
||||
(@tokens[i - <span class="hljs-number">1</span>].newLine <span class="hljs-keyword">or</span> @tokens[i - <span class="hljs-number">1</span>][<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span>)
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">action</span> = <span class="hljs-params">(token, i)</span> -></span>
|
||||
ifThens.pop() <span class="hljs-keyword">if</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> starter <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
@tokens.splice (<span class="hljs-keyword">if</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">','</span> <span class="hljs-keyword">then</span> i - <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> i), <span class="hljs-number">0</span>, outdent
|
||||
<span class="hljs-function">
|
||||
<span class="hljs-title">closeElseTag</span> = <span class="hljs-params">(tokens, i)</span> =></span>
|
||||
tlen = ifThens.length
|
||||
<span class="hljs-keyword">return</span> i <span class="hljs-keyword">unless</span> tlen > <span class="hljs-number">0</span>
|
||||
lastThen = ifThens.pop()
|
||||
[, outdentElse] = @indentation tokens[lastThen]</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
</div>
|
||||
<p>Insert <code>OUTDENT</code> to close inner <code>IF</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> outdentElse[<span class="hljs-number">1</span>] = tlen*<span class="hljs-number">2</span>
|
||||
tokens.splice(i, <span class="hljs-number">0</span>, outdentElse)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
</div>
|
||||
<p>Insert <code>OUTDENT</code> to close outer <code>IF</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> outdentElse[<span class="hljs-number">1</span>] = <span class="hljs-number">2</span>
|
||||
tokens.splice(i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, outdentElse)</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
</div>
|
||||
<p>Remove outdents from the end.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> @detectEnd i + <span class="hljs-number">2</span>,
|
||||
<span class="hljs-function"><span class="hljs-params">(token, i)</span> -></span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'OUTDENT'</span>, <span class="hljs-string">'TERMINATOR'</span>]
|
||||
(token, i) ->
|
||||
<span class="hljs-keyword">if</span> @tag(i) <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
tokens.splice i, <span class="hljs-number">2</span>
|
||||
i + <span class="hljs-number">2</span>
|
||||
|
||||
@scanTokens (token, i, tokens) ->
|
||||
[tag] = token
|
||||
conditionTag = tag <span class="hljs-keyword">in</span> [<span class="hljs-string">'->'</span>, <span class="hljs-string">'=>'</span>] <span class="hljs-keyword">and</span>
|
||||
@findTagsBackwards(i, [<span class="hljs-string">'IF'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'SWITCH'</span>, <span class="hljs-string">'WHEN'</span>, <span class="hljs-string">'LEADING_WHEN'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">'INDEX_START'</span>]) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (@findTagsBackwards i, [<span class="hljs-string">'THEN'</span>, <span class="hljs-string">'..'</span>, <span class="hljs-string">'...'</span>])
|
||||
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span>
|
||||
<span class="hljs-keyword">if</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
tokens.splice i, <span class="hljs-number">1</span>, @indentation()...
|
||||
@@ -1275,10 +1374,31 @@ blocks are added.</p>
|
||||
tokens.splice i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, indent, outdent
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> SINGLE_LINERS <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'INDENT'</span> <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> (tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>)
|
||||
<span class="hljs-keyword">not</span> (tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>) <span class="hljs-keyword">and</span>
|
||||
<span class="hljs-keyword">not</span> conditionTag
|
||||
starter = tag
|
||||
[indent, outdent] = @indentation tokens[i]
|
||||
indent.fromThen = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> starter <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
<span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
leading_switch_when = @findTagsBackwards(i, [<span class="hljs-string">'LEADING_WHEN'</span>]) <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>
|
||||
leading_if_then = @findTagsBackwards(i, [<span class="hljs-string">'IF'</span>]) <span class="hljs-keyword">and</span> @tag(i + <span class="hljs-number">1</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'IF'</span>
|
||||
ifThens.push i <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span> <span class="hljs-keyword">and</span> @findTagsBackwards(i, [<span class="hljs-string">'IF'</span>])</pre></div></div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-54">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
</div>
|
||||
<p><code>ELSE</code> tag is not closed.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'ELSE'</span> <span class="hljs-keyword">and</span> @tag(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'OUTDENT'</span>
|
||||
i = closeElseTag tokens, i
|
||||
tokens.splice i + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, indent
|
||||
@detectEnd i + <span class="hljs-number">2</span>, condition, action
|
||||
tokens.splice i, <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'THEN'</span>
|
||||
@@ -1288,11 +1408,11 @@ blocks are added.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-50">
|
||||
<li id="section-55">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-50">¶</a>
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
</div>
|
||||
<p>Tag postfix conditionals as such, so that we can parse them with a
|
||||
different precedence.</p>
|
||||
@@ -1320,11 +1440,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-51">
|
||||
<li id="section-56">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-51">¶</a>
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
</div>
|
||||
<p>Generate the indentation tokens, based on another token on the same line.</p>
|
||||
|
||||
@@ -1345,11 +1465,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-52">
|
||||
<li id="section-57">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-52">¶</a>
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
</div>
|
||||
<p>Look up a tag by token index.</p>
|
||||
|
||||
@@ -1360,11 +1480,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-53">
|
||||
<li id="section-58">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-53">¶</a>
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
</div>
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
@@ -1373,11 +1493,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-54">
|
||||
<li id="section-59">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-54">¶</a>
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1385,11 +1505,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-55">
|
||||
<li id="section-60">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-55">¶</a>
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
</div>
|
||||
<p>List of the token pairs that must be balanced.</p>
|
||||
|
||||
@@ -1410,11 +1530,11 @@ different precedence.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-56">
|
||||
<li id="section-61">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-56">¶</a>
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
</div>
|
||||
<p>The inverse mappings of <code>BALANCED_PAIRS</code> we’re trying to fix up, so we can
|
||||
look things up from either end.</p>
|
||||
@@ -1426,11 +1546,11 @@ look things up from either end.</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-57">
|
||||
<li id="section-62">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-57">¶</a>
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
</div>
|
||||
<p>The tokens that signal the start/end of a balanced pair.</p>
|
||||
|
||||
@@ -1446,11 +1566,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-58">
|
||||
<li id="section-63">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-58">¶</a>
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
</div>
|
||||
<p>Tokens that indicate the close of a clause of an expression.</p>
|
||||
|
||||
@@ -1461,11 +1581,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-59">
|
||||
<li id="section-64">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-59">¶</a>
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
</div>
|
||||
<p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p>
|
||||
|
||||
@@ -1476,11 +1596,11 @@ EXPRESSION_END = []
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-60">
|
||||
<li id="section-65">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-60">¶</a>
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
</div>
|
||||
<p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p>
|
||||
|
||||
@@ -1500,11 +1620,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-61">
|
||||
<li id="section-66">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-61">¶</a>
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
</div>
|
||||
<p>Tokens that always mark the end of an implicit call for single-liners.</p>
|
||||
|
||||
@@ -1516,11 +1636,11 @@ IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hlj
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-62">
|
||||
<li id="section-67">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-62">¶</a>
|
||||
<a class="pilcrow" href="#section-67">¶</a>
|
||||
</div>
|
||||
<p>Single-line flavors of block expressions that have unclosed endings.
|
||||
The grammar can’t disambiguate them, so we insert the implicit indentation.</p>
|
||||
@@ -1533,11 +1653,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-63">
|
||||
<li id="section-68">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-63">¶</a>
|
||||
<a class="pilcrow" href="#section-68">¶</a>
|
||||
</div>
|
||||
<p>Tokens that end a line.</p>
|
||||
|
||||
@@ -1548,11 +1668,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-64">
|
||||
<li id="section-69">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-64">¶</a>
|
||||
<a class="pilcrow" href="#section-69">¶</a>
|
||||
</div>
|
||||
<p>Tokens that close open calls when they follow a newline.</p>
|
||||
|
||||
@@ -1563,11 +1683,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-65">
|
||||
<li id="section-70">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-65">¶</a>
|
||||
<a class="pilcrow" href="#section-70">¶</a>
|
||||
</div>
|
||||
<p>Tokens that prevent a subsequent indent from ending implicit calls/objects</p>
|
||||
|
||||
@@ -1578,11 +1698,11 @@ SINGLE_CLOSERS = [<span class="hljs-string">'TERMINATOR'</span>, <span class="
|
||||
</li>
|
||||
|
||||
|
||||
<li id="section-66">
|
||||
<li id="section-71">
|
||||
<div class="annotation">
|
||||
|
||||
<div class="pilwrap ">
|
||||
<a class="pilcrow" href="#section-66">¶</a>
|
||||
<a class="pilcrow" href="#section-71">¶</a>
|
||||
</div>
|
||||
<p>Tokens that are swallowed up by the parser, never leading to code generation.
|
||||
You can spot these in <code>grammar.coffee</code> because the <code>o</code> function second
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1083
docs/v2/test.html
1083
docs/v2/test.html
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,31 @@
|
||||
## 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')
|
||||
```
|
||||
* This release fixes *all* currently open bugs, dating as far back as 2014, 2012 and 2011.
|
||||
* **Potential breaking change:** An inline `if` or `switch` statement with an ambiguous `else`, such as `if no then if yes then alert 1 else alert 2`, now compiles where the `else` always corresponds to the closest open `then`. Previously the behavior of an ambiguous `else` was unpredictable. If your code has any `if … then` or `switch … then` statements with multiple `then`s (and one or more `else`s) the compiled output might be different now, unless you had resolved ambiguity via parentheses. We made this change because the previous behavior was inconsistent and basically a bug: depending on what grammar was where, for example if there was an inline function or something that implied a block, the `else` might bind to an earlier `then` rather than a later `then`. Now an `else` essentially closes a block opened by a `then`, similar to closing an open parenthesis.
|
||||
* When a required `then` is missing, the error more accurately points out the location of the mistake.
|
||||
* An error is thrown when the `coffee` command is run in an environment that doesn’t support some ES2015 JavaScript features that the CoffeeScript compiler itself requires. This can happen if CoffeeScript is installed in Node older than version 6.
|
||||
* Destructuring with a non-final splat/spread, e.g. `[open, contents..., close] = tag.split('')` is now output using ES2015 rest syntax.
|
||||
* Functions named `get` or `set` can be used without parentheses in more cases, including when attached to `this` or `@` or `?.`; or when the first argument is an implicit object, e.g. `@set key: 'val'`.
|
||||
* Statements such as `break` can now be used inside parentheses, e.g. `(doSomething(); break) while condition` or `(pick(key); break) for key of obj`.
|
||||
* Bugfix for assigning to a property attached to `this`/`@` in destructuring, e.g. `({@prop = yes, @otherProp = no}) ->`.
|
||||
* Bugfix for incorrect errors being thrown about calling `super` with a parameter attached to `this` when said parameter is in a lower scope, e.g. `class Child extends Parent then constructor: -> super(-> @prop)`.
|
||||
* Bugfix to prevent a possible infinite loop when a `for` loop is given a variable to step by, e.g. `for x in [1..3] by step` (as opposed to `by 0.5` or some other primitive numeric value).
|
||||
* Bugfix to no longer declare iterator variables twice when evaluating a range, e.g. `end = 3; fn [0..end]`.
|
||||
* Bugfix for incorrect scope of variables in chained calls, e.g. `start(x = 3).then(-> x = 4)`.
|
||||
* Bugfix for incorrect scope of variables in a function passed to `do`, e.g. `for [1..3] then masked = 10; do -> alert masked`.
|
||||
* Bugfix to no longer throw a syntax error for a trailing comma in a function call, e.g. `fn arg1, arg2,`.
|
||||
* Bugfix for an expression in a property access, e.g. `a[!b in c..]`.
|
||||
* Bugfix to allow a line continuation backslash (`\`) at any point in a `for` line.
|
||||
|
||||
```
|
||||
releaseHeader('2017-12-29', '2.1.1', '2.1.0')
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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.
|
||||
@@ -77,7 +77,7 @@
|
||||
// all script tags with a content-type of `text/coffeescript`.
|
||||
// This happens on page load.
|
||||
runScripts = function() {
|
||||
var coffees, coffeetypes, execute, fn, i, index, j, len, s, script, scripts;
|
||||
var coffees, coffeetypes, execute, i, index, j, len, s, script, scripts;
|
||||
scripts = window.document.getElementsByTagName('script');
|
||||
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'];
|
||||
coffees = (function() {
|
||||
@@ -101,32 +101,31 @@
|
||||
return execute();
|
||||
}
|
||||
};
|
||||
fn = function(script, i) {
|
||||
var options, source;
|
||||
options = {
|
||||
literate: script.type === coffeetypes[1]
|
||||
};
|
||||
source = script.src || script.getAttribute('data-src');
|
||||
if (source) {
|
||||
options.filename = source;
|
||||
return CoffeeScript.load(source, function(param) {
|
||||
coffees[i] = param;
|
||||
return execute();
|
||||
}, options, true);
|
||||
} else {
|
||||
// `options.filename` defines the filename the source map appears as
|
||||
// in Developer Tools. If a script tag has an `id`, use that as the
|
||||
// filename; otherwise use `coffeescript`, or `coffeescript1` etc.,
|
||||
// leaving the first one unnumbered for the common case that there’s
|
||||
// only one CoffeeScript script block to parse.
|
||||
options.filename = script.id && script.id !== '' ? script.id : `coffeescript${(i !== 0 ? i : '')}`;
|
||||
options.sourceFiles = ['embedded'];
|
||||
return coffees[i] = [script.innerHTML, options];
|
||||
}
|
||||
};
|
||||
for (i = j = 0, len = coffees.length; j < len; i = ++j) {
|
||||
script = coffees[i];
|
||||
fn(script, i);
|
||||
(function(script, i) {
|
||||
var options, source;
|
||||
options = {
|
||||
literate: script.type === coffeetypes[1]
|
||||
};
|
||||
source = script.src || script.getAttribute('data-src');
|
||||
if (source) {
|
||||
options.filename = source;
|
||||
return CoffeeScript.load(source, function(param) {
|
||||
coffees[i] = param;
|
||||
return execute();
|
||||
}, options, true);
|
||||
} else {
|
||||
// `options.filename` defines the filename the source map appears as
|
||||
// in Developer Tools. If a script tag has an `id`, use that as the
|
||||
// filename; otherwise use `coffeescript`, or `coffeescript1` etc.,
|
||||
// leaving the first one unnumbered for the common case that there’s
|
||||
// only one CoffeeScript script block to parse.
|
||||
options.filename = script.id && script.id !== '' ? script.id : `coffeescript${(i !== 0 ? i : '')}`;
|
||||
options.sourceFiles = ['embedded'];
|
||||
return coffees[i] = [script.innerHTML, options];
|
||||
}
|
||||
})(script, i);
|
||||
}
|
||||
return execute();
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
@@ -97,7 +97,7 @@
|
||||
// Block and statements, which make up a line in a body. YieldReturn is a
|
||||
// statement, but not included in Statement because that results in an ambiguous
|
||||
// grammar.
|
||||
Line: [o('Expression'), o('Statement'), o('FuncDirective')],
|
||||
Line: [o('Expression'), o('ExpressionLine'), o('Statement'), o('FuncDirective')],
|
||||
FuncDirective: [o('YieldReturn'), o('AwaitReturn')],
|
||||
// Pure statements which cannot be expressions.
|
||||
Statement: [
|
||||
@@ -114,6 +114,10 @@
|
||||
// is one. Blocks serve as the building blocks of many other rules, making
|
||||
// them somewhat circular.
|
||||
Expression: [o('Value'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw'), o('Yield')],
|
||||
// Expressions which are written in single line and would otherwise require being
|
||||
// wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`,
|
||||
// `for x in do (obj) -> f obj when x > 8 then f x`
|
||||
ExpressionLine: [o('CodeLine'), o('IfLine'), o('OperationLine')],
|
||||
Yield: [
|
||||
o('YIELD',
|
||||
function() {
|
||||
@@ -407,6 +411,22 @@
|
||||
$1);
|
||||
})
|
||||
],
|
||||
// The Codeline is the **Code** node with **Line** instead of indented **Block**.
|
||||
CodeLine: [
|
||||
o('PARAM_START ParamList PARAM_END FuncGlyph Line',
|
||||
function() {
|
||||
return new Code($2,
|
||||
LOC(5)(Block.wrap([$5])),
|
||||
$4,
|
||||
LOC(1)(new Literal($1)));
|
||||
}),
|
||||
o('FuncGlyph Line',
|
||||
function() {
|
||||
return new Code([],
|
||||
LOC(2)(Block.wrap([$2])),
|
||||
$1);
|
||||
})
|
||||
],
|
||||
// CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
// functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [
|
||||
@@ -990,6 +1010,12 @@
|
||||
return new Range($2,
|
||||
$4,
|
||||
$3);
|
||||
}),
|
||||
o('[ ExpressionLine RangeDots Expression ]',
|
||||
function() {
|
||||
return new Range($2,
|
||||
$4,
|
||||
$3);
|
||||
})
|
||||
],
|
||||
// Array slice literals.
|
||||
@@ -1006,6 +1032,18 @@
|
||||
null,
|
||||
$2);
|
||||
}),
|
||||
o('ExpressionLine RangeDots Expression',
|
||||
function() {
|
||||
return new Range($1,
|
||||
$3,
|
||||
$2);
|
||||
}),
|
||||
o('ExpressionLine RangeDots',
|
||||
function() {
|
||||
return new Range($1,
|
||||
null,
|
||||
$2);
|
||||
}),
|
||||
o('RangeDots Expression',
|
||||
function() {
|
||||
return new Range(null,
|
||||
@@ -1046,6 +1084,7 @@
|
||||
// Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o('Expression'),
|
||||
o('ExpressionLine'),
|
||||
o('Splat'),
|
||||
o('...',
|
||||
function() {
|
||||
@@ -1117,10 +1156,16 @@
|
||||
// having the newlines wouldn't make sense.
|
||||
SimpleArgs: [
|
||||
o('Expression'),
|
||||
o('ExpressionLine'),
|
||||
o('SimpleArgs , Expression',
|
||||
function() {
|
||||
return [].concat($1,
|
||||
$3);
|
||||
}),
|
||||
o('SimpleArgs , ExpressionLine',
|
||||
function() {
|
||||
return [].concat($1,
|
||||
$3);
|
||||
})
|
||||
],
|
||||
// The variants of *try/catch/finally* exception handling blocks.
|
||||
@@ -1194,6 +1239,34 @@
|
||||
})
|
||||
],
|
||||
// The condition portion of a while loop.
|
||||
WhileLineSource: [
|
||||
o('WHILE ExpressionLine',
|
||||
function() {
|
||||
return new While($2);
|
||||
}),
|
||||
o('WHILE ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
})
|
||||
],
|
||||
WhileSource: [
|
||||
o('WHILE Expression',
|
||||
function() {
|
||||
@@ -1206,6 +1279,13 @@
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('WHILE ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
@@ -1214,6 +1294,14 @@
|
||||
});
|
||||
}),
|
||||
o('UNTIL Expression WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
}),
|
||||
o('UNTIL ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return new While($2,
|
||||
{
|
||||
@@ -1229,6 +1317,10 @@
|
||||
function() {
|
||||
return $1.addBody($2);
|
||||
}),
|
||||
o('WhileLineSource Block',
|
||||
function() {
|
||||
return $1.addBody($2);
|
||||
}),
|
||||
o('Statement WhileSource',
|
||||
function() {
|
||||
return $2.addBody(LOC(1)(Block.wrap([$1])));
|
||||
@@ -1270,6 +1362,11 @@
|
||||
function() {
|
||||
return new For($2,
|
||||
$1);
|
||||
}),
|
||||
o('ForLineBody Block',
|
||||
function() {
|
||||
return new For($2,
|
||||
$1);
|
||||
})
|
||||
],
|
||||
ForBody: [
|
||||
@@ -1295,6 +1392,23 @@
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
ForLineBody: [
|
||||
o('FOR Range BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: LOC(2)(new Value($2)),
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('ForStart ForLineSource',
|
||||
function() {
|
||||
$2.own = $1.own;
|
||||
$2.ownTag = $1.ownTag;
|
||||
$2.name = $1[0];
|
||||
$2.index = $1[1];
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
ForStart: [
|
||||
o('FOR ForVariables',
|
||||
function() {
|
||||
@@ -1359,6 +1473,13 @@
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FOROF Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1367,6 +1488,14 @@
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1374,6 +1503,13 @@
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1382,6 +1518,30 @@
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine BY Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1390,6 +1550,30 @@
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression',
|
||||
function() {
|
||||
return {
|
||||
@@ -1398,6 +1582,160 @@
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine WHEN Expression',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
})
|
||||
],
|
||||
ForLineSource: [
|
||||
o('FORIN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4
|
||||
};
|
||||
}),
|
||||
o('FOROF Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FOROF ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN Expression BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression WHEN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN Expression BY ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
guard: $6
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM Expression WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
guard: $4,
|
||||
from: true
|
||||
};
|
||||
}),
|
||||
o('FORFROM ExpressionLine WHEN ExpressionLine',
|
||||
function() {
|
||||
return {
|
||||
source: $2,
|
||||
@@ -1412,12 +1750,23 @@
|
||||
return new Switch($2,
|
||||
$4);
|
||||
}),
|
||||
o('SWITCH ExpressionLine INDENT Whens OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4);
|
||||
}),
|
||||
o('SWITCH Expression INDENT Whens ELSE Block OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4,
|
||||
$6);
|
||||
}),
|
||||
o('SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT',
|
||||
function() {
|
||||
return new Switch($2,
|
||||
$4,
|
||||
$6);
|
||||
}),
|
||||
o('SWITCH INDENT Whens OUTDENT',
|
||||
function() {
|
||||
return new Switch(null,
|
||||
@@ -1499,12 +1848,63 @@
|
||||
});
|
||||
})
|
||||
],
|
||||
IfBlockLine: [
|
||||
o('IF ExpressionLine Block',
|
||||
function() {
|
||||
return new If($2,
|
||||
$3,
|
||||
{
|
||||
type: $1
|
||||
});
|
||||
}),
|
||||
o('IfBlockLine ELSE IF ExpressionLine Block',
|
||||
function() {
|
||||
return $1.addElse(LOC(3,
|
||||
5)(new If($4,
|
||||
$5,
|
||||
{
|
||||
type: $3
|
||||
})));
|
||||
})
|
||||
],
|
||||
IfLine: [
|
||||
o('IfBlockLine'),
|
||||
o('IfBlockLine ELSE Block',
|
||||
function() {
|
||||
return $1.addElse($3);
|
||||
}),
|
||||
o('Statement POST_IF ExpressionLine',
|
||||
function() {
|
||||
return new If($3,
|
||||
LOC(1)(Block.wrap([$1])),
|
||||
{
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
}),
|
||||
o('Expression POST_IF ExpressionLine',
|
||||
function() {
|
||||
return new If($3,
|
||||
LOC(1)(Block.wrap([$1])),
|
||||
{
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
})
|
||||
],
|
||||
// Arithmetic and logical operators, working on one or more operands.
|
||||
// Here they are grouped by order of precedence. The actual precedence rules
|
||||
// are defined at the bottom of the page. It would be shorter if we could
|
||||
// combine most of these rules into a single generic *Operand OpSymbol Operand*
|
||||
// -type rule, but in order to make the precedence binding possible, separate
|
||||
// rules are necessary.
|
||||
OperationLine: [
|
||||
o('UNARY ExpressionLine',
|
||||
function() {
|
||||
return new Op($1,
|
||||
$2);
|
||||
})
|
||||
],
|
||||
Operation: [
|
||||
o('UNARY Expression',
|
||||
function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// Generated by CoffeeScript 2.2.1
|
||||
(function() {
|
||||
// Node.js Implementation
|
||||
var CoffeeScript, ext, fn, fs, helpers, i, len, path, ref, universalCompile, vm,
|
||||
var CoffeeScript, ext, fs, helpers, i, len, path, ref, universalCompile, vm,
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
CoffeeScript = require('./coffeescript');
|
||||
@@ -137,15 +137,14 @@
|
||||
// Throw error with deprecation warning when depending upon implicit `require.extensions` registration
|
||||
if (require.extensions) {
|
||||
ref = CoffeeScript.FILE_EXTENSIONS;
|
||||
fn = function(ext) {
|
||||
var base;
|
||||
return (base = require.extensions)[ext] != null ? base[ext] : base[ext] = function() {
|
||||
throw new Error(`Use CoffeeScript.register() or require the coffeescript/register module to require ${ext} files.`);
|
||||
};
|
||||
};
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
ext = ref[i];
|
||||
fn(ext);
|
||||
(function(ext) {
|
||||
var base;
|
||||
return (base = require.extensions)[ext] != null ? base[ext] : base[ext] = function() {
|
||||
throw new Error(`Use CoffeeScript.register() or require the coffeescript/register module to require ${ext} files.`);
|
||||
};
|
||||
})(ext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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,
|
||||
@@ -11,7 +11,8 @@
|
||||
// format that can be fed directly into [Jison](https://github.com/zaach/jison). These
|
||||
// are read by jison in the `parser.lexer` function defined in coffeescript.coffee.
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARABLE_LEFT_SIDE, COMPARE, COMPOUND_ASSIGN, CSX_ATTRIBUTE, CSX_FRAGMENT_IDENTIFIER, CSX_IDENTIFIER, CSX_INTERPOLATION, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INSIDE_CSX, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, attachCommentsToNode, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, merge, repeat, starts, throwSyntaxError,
|
||||
indexOf = [].indexOf;
|
||||
indexOf = [].indexOf,
|
||||
slice = [].slice;
|
||||
|
||||
({Rewriter, INVERSES} = require('./rewriter'));
|
||||
|
||||
@@ -111,7 +112,7 @@
|
||||
// referenced as property names here, so you can still do `jQuery.is()` even
|
||||
// though `is` means `===` otherwise.
|
||||
identifierToken() {
|
||||
var alias, colon, colonOffset, colonToken, id, idLength, inCSXTag, input, match, poppedToken, prev, prevprev, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, regExSuper, regex, sup, tag, tagToken;
|
||||
var alias, colon, colonOffset, colonToken, id, idLength, inCSXTag, input, match, poppedToken, prev, prevprev, ref, ref1, ref10, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, regExSuper, regex, sup, tag, tagToken;
|
||||
inCSXTag = this.atCSXTag();
|
||||
regex = inCSXTag ? CSX_ATTRIBUTE : IDENTIFIER;
|
||||
if (!(match = regex.exec(this.chunk))) {
|
||||
@@ -199,11 +200,11 @@
|
||||
// what CoffeeScript would normally interpret as calls to functions named
|
||||
// `get` or `set`, i.e. `get({foo: function () {}})`.
|
||||
} else if (tag === 'PROPERTY' && prev) {
|
||||
if (prev.spaced && (ref7 = prev[0], indexOf.call(CALLABLE, ref7) >= 0) && /^[gs]et$/.test(prev[1]) && this.tokens[this.tokens.length - 2][0] !== '.') {
|
||||
if (prev.spaced && (ref7 = prev[0], indexOf.call(CALLABLE, ref7) >= 0) && /^[gs]et$/.test(prev[1]) && this.tokens.length > 1 && ((ref8 = this.tokens[this.tokens.length - 2][0]) !== '.' && ref8 !== '?.' && ref8 !== '@')) {
|
||||
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
|
||||
} else {
|
||||
} else if (this.tokens.length > 2) {
|
||||
prevprev = this.tokens[this.tokens.length - 2];
|
||||
if (((ref8 = prev[0]) === '@' || ref8 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && this.tokens[this.tokens.length - 3][0] !== '.') {
|
||||
if (((ref9 = prev[0]) === '@' || ref9 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1]) && ((ref10 = this.tokens[this.tokens.length - 3][0]) !== '.' && ref10 !== '?.' && ref10 !== '@')) {
|
||||
this.error(`'${prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prevprev[2]);
|
||||
}
|
||||
}
|
||||
@@ -586,12 +587,16 @@
|
||||
// Keeps track of the level of indentation, because a single outdent token
|
||||
// can close multiple indents, so we need to know how far in we happen to be.
|
||||
lineToken(chunk = this.chunk) {
|
||||
var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size;
|
||||
var backslash, diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, prev, size;
|
||||
if (!(match = MULTI_DENT.exec(chunk))) {
|
||||
return 0;
|
||||
}
|
||||
indent = match[0];
|
||||
this.seenFor = false;
|
||||
prev = this.prev();
|
||||
backslash = (prev != null) && prev[0] === '\\';
|
||||
if (!(backslash && this.seenFor)) {
|
||||
this.seenFor = false;
|
||||
}
|
||||
if (!this.importSpecifierList) {
|
||||
this.seenImport = false;
|
||||
}
|
||||
@@ -1050,7 +1055,7 @@
|
||||
if (braceInterpolator) {
|
||||
// Turn the leading and trailing `{` and `}` into parentheses. Unnecessary
|
||||
// parentheses will be removed later.
|
||||
open = nested[0], close = nested[nested.length - 1];
|
||||
[open] = nested, [close] = slice.call(nested, -1);
|
||||
open[0] = open[1] = '(';
|
||||
close[0] = close[1] = ')';
|
||||
close.origin = ['', 'end of interpolation', close[2]];
|
||||
@@ -1075,7 +1080,7 @@
|
||||
length: delimiter.length
|
||||
});
|
||||
}
|
||||
firstToken = tokens[0], lastToken = tokens[tokens.length - 1];
|
||||
[firstToken] = tokens, [lastToken] = slice.call(tokens, -1);
|
||||
firstToken[2].first_column -= delimiter.length;
|
||||
if (lastToken[1].substr(-1) === '\n') {
|
||||
lastToken[2].last_line += 1;
|
||||
@@ -1176,7 +1181,7 @@
|
||||
this.tokens.push(...tokensToPush);
|
||||
}
|
||||
if (lparen) {
|
||||
lastToken = tokens[tokens.length - 1];
|
||||
[lastToken] = slice.call(tokens, -1);
|
||||
lparen.origin = [
|
||||
'STRING',
|
||||
null,
|
||||
@@ -1202,7 +1207,7 @@
|
||||
// correctly balanced throughout the course of the token stream.
|
||||
pair(tag) {
|
||||
var lastIndent, prev, ref, ref1, wanted;
|
||||
ref = this.ends, prev = ref[ref.length - 1];
|
||||
ref = this.ends, [prev] = slice.call(ref, -1);
|
||||
if (tag !== (wanted = prev != null ? prev.tag : void 0)) {
|
||||
if ('OUTDENT' !== wanted) {
|
||||
this.error(`unmatched ${tag}`);
|
||||
@@ -1212,7 +1217,7 @@
|
||||
// el.click((event) ->
|
||||
// el.hide())
|
||||
|
||||
ref1 = this.indents, lastIndent = ref1[ref1.length - 1];
|
||||
ref1 = this.indents, [lastIndent] = slice.call(ref1, -1);
|
||||
this.outdentToken(lastIndent, true);
|
||||
return this.pair(tag);
|
||||
}
|
||||
@@ -1238,7 +1243,7 @@
|
||||
lineCount = count(string, '\n');
|
||||
column = this.chunkColumn;
|
||||
if (lineCount > 0) {
|
||||
ref = string.split('\n'), lastLine = ref[ref.length - 1];
|
||||
ref = string.split('\n'), [lastLine] = slice.call(ref, -1);
|
||||
column = lastLine.length;
|
||||
} else {
|
||||
column += string.length;
|
||||
@@ -1279,14 +1284,14 @@
|
||||
// Peek at the last tag in the token stream.
|
||||
tag() {
|
||||
var ref, token;
|
||||
ref = this.tokens, token = ref[ref.length - 1];
|
||||
ref = this.tokens, [token] = slice.call(ref, -1);
|
||||
return token != null ? token[0] : void 0;
|
||||
}
|
||||
|
||||
// Peek at the last value in the token stream.
|
||||
value(useOrigin = false) {
|
||||
var ref, ref1, token;
|
||||
ref = this.tokens, token = ref[ref.length - 1];
|
||||
ref = this.tokens, [token] = slice.call(ref, -1);
|
||||
if (useOrigin && ((token != null ? token.origin : void 0) != null)) {
|
||||
return (ref1 = token.origin) != null ? ref1[1] : void 0;
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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),
|
||||
@@ -7,7 +7,7 @@
|
||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, moveComments, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||
indexOf = [].indexOf,
|
||||
splice = [].splice,
|
||||
slice = [].slice;
|
||||
slice1 = [].slice;
|
||||
|
||||
Error.stackTraceLimit = 2e308;
|
||||
|
||||
@@ -721,7 +721,7 @@
|
||||
fragments = node.compileToFragments(o);
|
||||
if (!node.isStatement(o)) {
|
||||
fragments = indentInitial(fragments, this);
|
||||
lastFragment = fragments[fragments.length - 1];
|
||||
[lastFragment] = slice1.call(fragments, -1);
|
||||
if (!(lastFragment.code === '' || lastFragment.isComment)) {
|
||||
fragments.push(this.makeCode(';'));
|
||||
}
|
||||
@@ -849,7 +849,7 @@
|
||||
// generates output indented by two spaces; so all we need to do is
|
||||
// search for a `code` property that begins with at least two spaces.
|
||||
fragmentIndent = '';
|
||||
ref1 = fragments.slice(0, fragmentIndex + 1);
|
||||
ref1 = fragments.slice(0, (fragmentIndex + 1));
|
||||
for (k = ref1.length - 1; k >= 0; k += -1) {
|
||||
pastFragment = ref1[k];
|
||||
indent = /^ {2,}/m.exec(pastFragment.code);
|
||||
@@ -874,7 +874,7 @@
|
||||
}
|
||||
return results;
|
||||
})()).join(`\n${fragmentIndent}`).replace(/^(\s*)$/gm, '');
|
||||
ref2 = fragments.slice(0, fragmentIndex + 1);
|
||||
ref2 = fragments.slice(0, (fragmentIndex + 1));
|
||||
for (pastFragmentIndex = l = ref2.length - 1; l >= 0; pastFragmentIndex = l += -1) {
|
||||
pastFragment = ref2[pastFragmentIndex];
|
||||
newLineIndex = pastFragment.code.lastIndexOf('\n');
|
||||
@@ -1200,8 +1200,8 @@
|
||||
if (this.expression) {
|
||||
answer = this.expression.compileToFragments(o, LEVEL_PAREN);
|
||||
unshiftAfterComments(answer, this.makeCode(`${this.tab}return `));
|
||||
// Since the `return` got indented by `@tab`, preceding comments that are
|
||||
// multiline need to be indented.
|
||||
// Since the `return` got indented by `@tab`, preceding comments that are
|
||||
// multiline need to be indented.
|
||||
for (j = 0, len1 = answer.length; j < len1; j++) {
|
||||
fragment = answer[j];
|
||||
if (fragment.isHereComment && indexOf.call(fragment.code, '\n') >= 0) {
|
||||
@@ -1267,6 +1267,15 @@
|
||||
if (!props && base instanceof Value) {
|
||||
return base;
|
||||
}
|
||||
if (base instanceof Parens && base.contains(function(n) {
|
||||
return n instanceof StatementLiteral;
|
||||
})) {
|
||||
// When `Parens` block includes a `StatementLiteral` (e.g. `(b; break) for a in arr`),
|
||||
// it won't compile since `Parens` (`(b; break)`) is compiled as `Value` and
|
||||
// pure statement (`break`) can't be used in an expression.
|
||||
// For this reasons, we return `Block` instead of `Parens`.
|
||||
return base.unwrap();
|
||||
}
|
||||
this.base = base;
|
||||
this.properties = props || [];
|
||||
if (tag) {
|
||||
@@ -1380,7 +1389,7 @@
|
||||
|
||||
isSplice() {
|
||||
var lastProp, ref1;
|
||||
ref1 = this.properties, lastProp = ref1[ref1.length - 1];
|
||||
ref1 = this.properties, [lastProp] = slice1.call(ref1, -1);
|
||||
return lastProp instanceof Slice;
|
||||
}
|
||||
|
||||
@@ -1404,7 +1413,7 @@
|
||||
// `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c`
|
||||
cacheReference(o) {
|
||||
var base, bref, name, nref, ref1;
|
||||
ref1 = this.properties, name = ref1[ref1.length - 1];
|
||||
ref1 = this.properties, [name] = slice1.call(ref1, -1);
|
||||
if (this.properties.length < 2 && !this.base.shouldCache() && !(name != null ? name.shouldCache() : void 0)) {
|
||||
return [this, this]; // `a` `a.b`
|
||||
}
|
||||
@@ -1432,7 +1441,17 @@
|
||||
var fragments, j, len1, prop, props;
|
||||
this.base.front = this.front;
|
||||
props = this.properties;
|
||||
fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null));
|
||||
if (props.length && (this.base.cached != null)) {
|
||||
// Cached fragments enable correct order of the compilation,
|
||||
// and reuse of variables in the scope.
|
||||
// Example:
|
||||
// `a(x = 5).b(-> x = 6)` should compile in the same order as
|
||||
// `a(x = 5); b(-> x = 6)`
|
||||
// (see issue #4437, https://github.com/jashkenas/coffeescript/issues/4437)
|
||||
fragments = this.base.cached;
|
||||
} else {
|
||||
fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null));
|
||||
}
|
||||
if (props.length && SIMPLENUM.test(fragmentsToText(fragments))) {
|
||||
fragments.push(this.makeCode('.'));
|
||||
}
|
||||
@@ -1499,7 +1518,7 @@
|
||||
constructor({
|
||||
content: content1,
|
||||
newLine: newLine1,
|
||||
unshift: unshift
|
||||
unshift
|
||||
}) {
|
||||
super();
|
||||
this.content = content1;
|
||||
@@ -1546,7 +1565,7 @@
|
||||
constructor({
|
||||
content: content1,
|
||||
newLine: newLine1,
|
||||
unshift: unshift
|
||||
unshift
|
||||
}) {
|
||||
super();
|
||||
this.content = content1;
|
||||
@@ -1681,7 +1700,7 @@
|
||||
|
||||
// Compile a vanilla function call.
|
||||
compileNode(o) {
|
||||
var arg, argIndex, compiledArgs, fragments, j, len1, ref1, ref2;
|
||||
var arg, argCode, argIndex, cache, compiledArgs, fragments, j, len1, ref1, ref2, ref3, ref4, varAccess;
|
||||
if (this.csx) {
|
||||
return this.compileCSX(o);
|
||||
}
|
||||
@@ -1689,9 +1708,35 @@
|
||||
ref1.front = this.front;
|
||||
}
|
||||
compiledArgs = [];
|
||||
ref2 = this.args;
|
||||
for (argIndex = j = 0, len1 = ref2.length; j < len1; argIndex = ++j) {
|
||||
arg = ref2[argIndex];
|
||||
// If variable is `Accessor` fragments are cached and used later
|
||||
// in `Value::compileNode` to ensure correct order of the compilation,
|
||||
// and reuse of variables in the scope.
|
||||
// Example:
|
||||
// `a(x = 5).b(-> x = 6)` should compile in the same order as
|
||||
// `a(x = 5); b(-> x = 6)`
|
||||
// (see issue #4437, https://github.com/jashkenas/coffeescript/issues/4437)
|
||||
varAccess = ((ref2 = this.variable) != null ? (ref3 = ref2.properties) != null ? ref3[0] : void 0 : void 0) instanceof Access;
|
||||
argCode = (function() {
|
||||
var j, len1, ref4, results;
|
||||
ref4 = this.args || [];
|
||||
results = [];
|
||||
for (j = 0, len1 = ref4.length; j < len1; j++) {
|
||||
arg = ref4[j];
|
||||
if (arg instanceof Code) {
|
||||
results.push(arg);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}).call(this);
|
||||
if (argCode.length > 0 && varAccess && !this.variable.base.cached) {
|
||||
[cache] = this.variable.base.cache(o, LEVEL_ACCESS, function() {
|
||||
return false;
|
||||
});
|
||||
this.variable.base.cached = cache;
|
||||
}
|
||||
ref4 = this.args;
|
||||
for (argIndex = j = 0, len1 = ref4.length; j < len1; argIndex = ++j) {
|
||||
arg = ref4[argIndex];
|
||||
if (argIndex) {
|
||||
compiledArgs.push(this.makeCode(", "));
|
||||
}
|
||||
@@ -1986,7 +2031,7 @@
|
||||
// When compiled normally, the range returns the contents of the *for loop*
|
||||
// needed to iterate over the values in the range. Used by comprehensions.
|
||||
compileNode(o) {
|
||||
var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, stepPart, to, varPart;
|
||||
var cond, condPart, from, gt, idx, idxName, known, lowerBound, lt, namedIndex, stepCond, stepPart, to, upperBound, varPart;
|
||||
if (!this.fromVar) {
|
||||
this.compileVariables(o);
|
||||
}
|
||||
@@ -1998,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}`;
|
||||
}
|
||||
@@ -2007,7 +2052,15 @@
|
||||
}
|
||||
[lt, gt] = [`${idx} <${this.equals}`, `${idx} >${this.equals}`];
|
||||
// Generate the condition.
|
||||
condPart = this.stepNum != null ? this.stepNum > 0 ? `${lt} ${this.toVar}` : `${gt} ${this.toVar}` : known ? ([from, to] = [this.fromNum, this.toNum], from <= to ? `${lt} ${to}` : `${gt} ${to}`) : (cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`, `${cond} ? ${lt} ${this.toVar} : ${gt} ${this.toVar}`);
|
||||
[from, to] = [this.fromNum, this.toNum];
|
||||
// Always check if the `step` isn't zero to avoid the infinite loop.
|
||||
stepCond = this.stepNum ? `${this.stepNum} !== 0` : `${this.stepVar} !== 0`;
|
||||
condPart = known ? this.step == null ? from <= to ? `${lt} ${to}` : `${gt} ${ // from < to
|
||||
to}` : (lowerBound = `${from} <= ${idx} && ${lt} ${// from > to
|
||||
to}`, upperBound = `${from} >= ${idx} && ${gt} ${to}`, from <= to ? `${stepCond} && ${lowerBound}` : `${stepCond} && ${// from < to
|
||||
upperBound}`) : (lowerBound = `${this.fromVar} <= ${idx} && ${lt} ${// from > to
|
||||
this.toVar}`, upperBound = `${this.fromVar} >= ${idx} && ${gt} ${this.toVar}`, `${stepCond} && (${this.fromVar} <= ${this.toVar} ? ${lowerBound} : ${upperBound})`);
|
||||
cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`;
|
||||
// Generate the step.
|
||||
stepPart = this.stepVar ? `${idx} += ${this.stepVar}` : known ? namedIndex ? from <= to ? `++${idx}` : `--${idx}` : from <= to ? `${idx}++` : `${idx}--` : namedIndex ? `${cond} ? ++${idx} : --${idx}` : `${cond} ? ${idx}++ : ${idx}--`;
|
||||
if (namedIndex) {
|
||||
@@ -2022,11 +2075,11 @@
|
||||
|
||||
// When used as a value, expand the range into the equivalent array.
|
||||
compileArray(o) {
|
||||
var args, body, cond, hasArgs, i, idt, j, known, post, pre, range, ref1, ref2, result, results, vars;
|
||||
var args, body, cond, hasArgs, i, idt, known, post, pre, range, ref1, ref2, result, vars;
|
||||
known = (this.fromNum != null) && (this.toNum != null);
|
||||
if (known && Math.abs(this.fromNum - this.toNum) <= 20) {
|
||||
range = (function() {
|
||||
results = [];
|
||||
var results = [];
|
||||
for (var j = ref1 = this.fromNum, ref2 = this.toNum; ref1 <= ref2 ? j <= ref2 : j >= ref2; ref1 <= ref2 ? j++ : j--){ results.push(j); }
|
||||
return results;
|
||||
}).apply(this);
|
||||
@@ -2037,10 +2090,13 @@
|
||||
}
|
||||
idt = this.tab + TAB;
|
||||
i = o.scope.freeVariable('i', {
|
||||
single: true
|
||||
single: true,
|
||||
reserve: false
|
||||
});
|
||||
result = o.scope.freeVariable('results');
|
||||
pre = `\n${idt}${result} = [];`;
|
||||
result = o.scope.freeVariable('results', {
|
||||
reserve: false
|
||||
});
|
||||
pre = `\n${idt}var ${result} = [];`;
|
||||
if (known) {
|
||||
o.index = i;
|
||||
body = fragmentsToText(this.compileNode(o));
|
||||
@@ -2085,8 +2141,14 @@
|
||||
compileNode(o) {
|
||||
var compiled, compiledText, from, fromCompiled, to, toStr;
|
||||
({to, from} = this.range);
|
||||
fromCompiled = from && from.compileToFragments(o, LEVEL_PAREN) || [this.makeCode('0')];
|
||||
// TODO: jwalton - move this into the 'if'?
|
||||
// Handle an expression in the property access, e.g. `a[!b in c..]`.
|
||||
if (from != null ? from.shouldCache() : void 0) {
|
||||
from = new Value(new Parens(from));
|
||||
}
|
||||
if (to != null ? to.shouldCache() : void 0) {
|
||||
to = new Value(new Parens(to));
|
||||
}
|
||||
fromCompiled = (from != null ? from.compileToFragments(o, LEVEL_PAREN) : void 0) || [this.makeCode('0')];
|
||||
if (to) {
|
||||
compiled = to.compileToFragments(o, LEVEL_PAREN);
|
||||
compiledText = fragmentsToText(compiled);
|
||||
@@ -2612,7 +2674,7 @@
|
||||
if (!this.variable) {
|
||||
return null;
|
||||
}
|
||||
ref1 = this.variable.properties, tail = ref1[ref1.length - 1];
|
||||
ref1 = this.variable.properties, [tail] = slice1.call(ref1, -1);
|
||||
node = tail ? tail instanceof Access && tail.name : this.variable.base;
|
||||
if (!(node instanceof IdentifierLiteral || node instanceof PropertyName)) {
|
||||
return null;
|
||||
@@ -3231,7 +3293,7 @@
|
||||
// we've been assigned to, for correct internal references. If the variable
|
||||
// has not been seen yet within the current scope, declare it.
|
||||
compileNode(o) {
|
||||
var answer, compiledName, hasSplat, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
|
||||
var answer, compiledName, hasSplat, isValue, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase;
|
||||
isValue = this.variable instanceof Value;
|
||||
if (isValue) {
|
||||
// When compiling `@variable`, remember if it is part of a function parameter.
|
||||
@@ -3314,7 +3376,7 @@
|
||||
if (this.value.isStatic) {
|
||||
this.value.name = this.variable.properties[0];
|
||||
} else if (((ref3 = this.variable.properties) != null ? ref3.length : void 0) >= 2) {
|
||||
ref4 = this.variable.properties, properties = 3 <= ref4.length ? slice.call(ref4, 0, j = ref4.length - 2) : (j = 0, []), prototype = ref4[j++], name = ref4[j++];
|
||||
ref4 = this.variable.properties, [...properties] = ref4, [prototype, name] = splice.call(properties, -2);
|
||||
if (((ref5 = prototype.name) != null ? ref5.value : void 0) === 'prototype') {
|
||||
this.value.name = name;
|
||||
}
|
||||
@@ -3461,7 +3523,7 @@
|
||||
// Brief implementation of recursive pattern matching, when assigning array or
|
||||
// object literals to a value. Peeks at their properties to assign inner names.
|
||||
compileDestructuring(o) {
|
||||
var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, rest, top, val, value, vvar, vvarText;
|
||||
var assignObjects, assigns, code, compSlice, compSplice, complexObjects, expIdx, expans, fragments, hasObjAssigns, hasObjSpreads, i, isArray, isExpans, isObject, isSplat, leftObjs, loopObjects, obj, objIsUnassignable, objects, olen, processObjects, ref, refExp, restVar, rightObjs, slicer, splats, splatsAndExpans, top, value, vvar, vvarText;
|
||||
top = o.level === LEVEL_TOP;
|
||||
({value} = this);
|
||||
({objects} = this.variable.base);
|
||||
@@ -3481,53 +3543,45 @@
|
||||
if (olen === 1 && obj instanceof Expansion) {
|
||||
obj.error('Destructuring assignment has no target');
|
||||
}
|
||||
isObject = this.variable.isObject();
|
||||
// Special case for when there's only one thing destructured off of
|
||||
// something. `{a} = b`, `[a] = b`, `{a: b} = c`
|
||||
if (top && olen === 1 && !(obj instanceof Splat)) {
|
||||
// Pick the property straight off the value when there’s just one to pick
|
||||
// (no need to cache the value into a variable).
|
||||
defaultValue = void 0;
|
||||
if (obj instanceof Assign && obj.context === 'object') {
|
||||
({
|
||||
// A regular object pattern-match.
|
||||
variable: {
|
||||
base: idx
|
||||
},
|
||||
value: obj
|
||||
} = obj);
|
||||
if (obj instanceof Assign) {
|
||||
defaultValue = obj.value;
|
||||
obj = obj.variable;
|
||||
// Count all `Splats`: [a, b, c..., d, e]
|
||||
splats = (function() {
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (i = j = 0, len1 = objects.length; j < len1; i = ++j) {
|
||||
obj = objects[i];
|
||||
if (obj instanceof Splat) {
|
||||
results.push(i);
|
||||
}
|
||||
} else {
|
||||
if (obj instanceof Assign) {
|
||||
defaultValue = obj.value;
|
||||
obj = obj.variable;
|
||||
}
|
||||
return results;
|
||||
})();
|
||||
// Count all `Expansions`: [a, b, ..., c, d]
|
||||
expans = (function() {
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (i = j = 0, len1 = objects.length; j < len1; i = ++j) {
|
||||
obj = objects[i];
|
||||
if (obj instanceof Expansion) {
|
||||
results.push(i);
|
||||
}
|
||||
// A shorthand `{a, b, @c} = val` pattern-match.
|
||||
// A regular array pattern-match.
|
||||
idx = isObject ? obj.this ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new NumberLiteral(0);
|
||||
}
|
||||
acc = idx.unwrap() instanceof PropertyName;
|
||||
value = new Value(value);
|
||||
value.properties.push(new (acc ? Access : Index)(idx));
|
||||
message = isUnassignable(obj.unwrap().value);
|
||||
if (message) {
|
||||
obj.error(message);
|
||||
}
|
||||
if (defaultValue) {
|
||||
defaultValue.isDefaultValue = true;
|
||||
value = new Op('?', value, defaultValue);
|
||||
}
|
||||
return new Assign(obj, value, null, {
|
||||
param: this.param
|
||||
}).compileToFragments(o, LEVEL_TOP);
|
||||
return results;
|
||||
})();
|
||||
// Combine splats and expansions.
|
||||
splatsAndExpans = [...splats, ...expans];
|
||||
// Show error if there is more than one `Splat`, or `Expansion`.
|
||||
// Examples: [a, b, c..., d, e, f...], [a, b, ..., c, d, ...], [a, b, ..., c, d, e...]
|
||||
if (splatsAndExpans.length > 1) {
|
||||
// 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 != 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);
|
||||
vvarText = fragmentsToText(vvar);
|
||||
assigns = [];
|
||||
expandedIdx = false;
|
||||
// At this point, there are several things to destructure. So the `fn()` in
|
||||
// `{a, b} = fn()` must be cached, for example. Make vvar into a simple
|
||||
// variable if it isn’t already.
|
||||
@@ -3537,100 +3591,176 @@
|
||||
vvar = [this.makeCode(ref)];
|
||||
vvarText = ref;
|
||||
}
|
||||
// And here comes the big loop that handles all of these cases:
|
||||
// `[a, b] = c`
|
||||
// `[a..., b] = c`
|
||||
// `[..., a, b] = c`
|
||||
// `[@a, b] = c`
|
||||
// `[a = 1, b] = c`
|
||||
// `{a, b} = c`
|
||||
// `{@a, b} = c`
|
||||
// `{a = 1, b} = c`
|
||||
// etc.
|
||||
for (i = j = 0, len1 = objects.length; j < len1; i = ++j) {
|
||||
obj = objects[i];
|
||||
idx = i;
|
||||
if (!expandedIdx && obj instanceof Splat) {
|
||||
name = obj.name.unwrap().value;
|
||||
obj = obj.unwrap();
|
||||
val = `${olen} <= ${vvarText}.length ? ${utility('slice', o)}.call(${vvarText}, ${i}`;
|
||||
rest = olen - i - 1;
|
||||
if (rest !== 0) {
|
||||
ivar = o.scope.freeVariable('i', {
|
||||
single: true
|
||||
});
|
||||
val += `, ${ivar} = ${vvarText}.length - ${rest}) : (${ivar} = ${i}, [])`;
|
||||
} else {
|
||||
val += ") : []";
|
||||
slicer = function(type) {
|
||||
return function(vvar, start, end = false) {
|
||||
var args, slice;
|
||||
args = [new IdentifierLiteral(vvar), new NumberLiteral(start)];
|
||||
if (end) {
|
||||
args.push(new NumberLiteral(end));
|
||||
}
|
||||
val = new Literal(val);
|
||||
expandedIdx = `${ivar}++`;
|
||||
} else if (!expandedIdx && obj instanceof Expansion) {
|
||||
rest = olen - i - 1;
|
||||
if (rest !== 0) {
|
||||
if (rest === 1) {
|
||||
expandedIdx = `${vvarText}.length - 1`;
|
||||
} else {
|
||||
ivar = o.scope.freeVariable('i', {
|
||||
single: true
|
||||
});
|
||||
val = new Literal(`${ivar} = ${vvarText}.length - ${rest}`);
|
||||
expandedIdx = `${ivar}++`;
|
||||
assigns.push(val.compileToFragments(o, LEVEL_LIST));
|
||||
}
|
||||
slice = new Value(new IdentifierLiteral(utility(type, o)), [new Access(new PropertyName('call'))]);
|
||||
return new Value(new Call(slice, args));
|
||||
};
|
||||
};
|
||||
// Helper which outputs `[].slice` code.
|
||||
compSlice = slicer("slice");
|
||||
// Helper which outputs `[].splice` code.
|
||||
compSplice = slicer("splice");
|
||||
// Check if `objects` array contains object spread (`{a, r...}`), e.g. `[a, b, {c, r...}]`.
|
||||
hasObjSpreads = function(objs) {
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (i = j = 0, len1 = objs.length; j < len1; i = ++j) {
|
||||
obj = objs[i];
|
||||
if (obj.base instanceof Obj && obj.base.hasSplat()) {
|
||||
results.push(i);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
if (obj instanceof Splat || obj instanceof Expansion) {
|
||||
obj.error("multiple splats/expansions are disallowed in an assignment");
|
||||
}
|
||||
return results;
|
||||
};
|
||||
// Check if `objects` array contains any instance of `Assign`, e.g. {a:1}.
|
||||
hasObjAssigns = function(objs) {
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (i = j = 0, len1 = objs.length; j < len1; i = ++j) {
|
||||
obj = objs[i];
|
||||
if (obj instanceof Assign && obj.context === 'object') {
|
||||
results.push(i);
|
||||
}
|
||||
defaultValue = void 0;
|
||||
}
|
||||
return results;
|
||||
};
|
||||
// Check if `objects` array contains any unassignable object.
|
||||
objIsUnassignable = function(objs) {
|
||||
var j, len1;
|
||||
for (j = 0, len1 = objs.length; j < len1; j++) {
|
||||
obj = objs[j];
|
||||
if (!obj.isAssignable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// `objects` are complex when there is object spread ({a...}), object assign ({a:1}),
|
||||
// unassignable object, or just a single node.
|
||||
complexObjects = function(objs) {
|
||||
return hasObjSpreads(objs).length || hasObjAssigns(objs).length || objIsUnassignable(objs) || olen === 1;
|
||||
};
|
||||
// "Complex" `objects` are processed in a loop.
|
||||
// Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
|
||||
loopObjects = (objs, vvar, vvarTxt) => {
|
||||
var acc, idx, j, len1, message, objSpreads, results, vval;
|
||||
objSpreads = hasObjSpreads(objs);
|
||||
results = [];
|
||||
for (i = j = 0, len1 = objs.length; j < len1; i = ++j) {
|
||||
obj = objs[i];
|
||||
if (obj instanceof Elision) {
|
||||
// `Elision` can be skipped.
|
||||
continue;
|
||||
}
|
||||
// If `obj` is {a: 1}
|
||||
if (obj instanceof Assign && obj.context === 'object') {
|
||||
({
|
||||
// A regular object pattern-match.
|
||||
variable: {
|
||||
base: idx
|
||||
},
|
||||
value: obj
|
||||
value: vvar
|
||||
} = obj);
|
||||
if (obj instanceof Assign) {
|
||||
defaultValue = obj.value;
|
||||
obj = obj.variable;
|
||||
if (vvar instanceof Assign) {
|
||||
({
|
||||
variable: vvar
|
||||
} = vvar);
|
||||
}
|
||||
idx = vvar.this ? vvar.properties[0].name : new PropertyName(vvar.unwrap().value);
|
||||
acc = idx.unwrap() instanceof PropertyName;
|
||||
vval = new Value(value, [new (acc ? Access : Index)(idx)]);
|
||||
} else {
|
||||
if (obj instanceof Assign) {
|
||||
defaultValue = obj.value;
|
||||
obj = obj.variable;
|
||||
}
|
||||
// A shorthand `{a, b, @c} = val` pattern-match.
|
||||
// A regular array pattern-match.
|
||||
idx = isObject ? obj.this ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new Literal(expandedIdx || idx);
|
||||
// `obj` is [a...], {a...} or a
|
||||
vvar = (function() {
|
||||
switch (false) {
|
||||
case !(obj instanceof Splat):
|
||||
return new Value(obj.name);
|
||||
case indexOf.call(objSpreads, i) < 0:
|
||||
return new Value(obj.base);
|
||||
default:
|
||||
return obj;
|
||||
}
|
||||
})();
|
||||
vval = (function() {
|
||||
switch (false) {
|
||||
case !(obj instanceof Splat):
|
||||
return compSlice(vvarTxt, i);
|
||||
default:
|
||||
return new Value(new Literal(vvarTxt), [new Index(new NumberLiteral(i))]);
|
||||
}
|
||||
})();
|
||||
}
|
||||
name = obj.unwrap().value;
|
||||
acc = idx.unwrap() instanceof PropertyName;
|
||||
val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]);
|
||||
if (defaultValue) {
|
||||
defaultValue.isDefaultValue = true;
|
||||
val = new Op('?', val, defaultValue);
|
||||
}
|
||||
}
|
||||
if (name != null) {
|
||||
message = isUnassignable(name);
|
||||
message = isUnassignable(vvar.unwrap().value);
|
||||
if (message) {
|
||||
obj.error(message);
|
||||
vvar.error(message);
|
||||
}
|
||||
}
|
||||
if (!(obj instanceof Elision)) {
|
||||
assigns.push(new Assign(obj, val, null, {
|
||||
results.push(assigns.push(new Assign(vvar, vval, null, {
|
||||
param: this.param,
|
||||
subpattern: true
|
||||
}).compileToFragments(o, LEVEL_LIST));
|
||||
} else {
|
||||
if (expandedIdx) {
|
||||
// Output `Elision` only if `idx` is `i++`, e.g. expandedIdx.
|
||||
assigns.push(idx.compileToFragments(o, LEVEL_LIST));
|
||||
}
|
||||
}).compileToFragments(o, LEVEL_LIST)));
|
||||
}
|
||||
return results;
|
||||
};
|
||||
// "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
|
||||
assignObjects = (objs, vvar, vvarTxt) => {
|
||||
var vval;
|
||||
vvar = new Value(new Arr(objs, true));
|
||||
vval = vvarTxt instanceof Value ? vvarTxt : new Value(new Literal(vvarTxt));
|
||||
return assigns.push(new Assign(vvar, vval, null, {
|
||||
param: this.param,
|
||||
subpattern: true
|
||||
}).compileToFragments(o, LEVEL_LIST));
|
||||
};
|
||||
processObjects = function(objs, vvar, vvarTxt) {
|
||||
if (complexObjects(objs)) {
|
||||
return loopObjects(objs, vvar, vvarTxt);
|
||||
} else {
|
||||
return assignObjects(objs, vvar, vvarTxt);
|
||||
}
|
||||
};
|
||||
// In case there is `Splat` or `Expansion` in `objects`,
|
||||
// we can split array in two simple subarrays.
|
||||
// `Splat` [a, b, c..., d, e] can be split into [a, b, c...] and [d, e].
|
||||
// `Expansion` [a, b, ..., c, d] can be split into [a, b] and [c, d].
|
||||
// Examples:
|
||||
// a) `Splat`
|
||||
// CS: [a, b, c..., d, e] = arr
|
||||
// JS: [a, b, ...c] = arr, [d, e] = splice.call(c, -2)
|
||||
// b) `Expansion`
|
||||
// CS: [a, b, ..., d, e] = arr
|
||||
// JS: [a, b] = arr, [d, e] = slice.call(arr, -2)
|
||||
if (splatsAndExpans.length) {
|
||||
expIdx = splatsAndExpans[0];
|
||||
leftObjs = objects.slice(0, expIdx + (isSplat ? 1 : 0));
|
||||
rightObjs = objects.slice(expIdx + 1);
|
||||
if (leftObjs.length !== 0) {
|
||||
processObjects(leftObjs, vvar, vvarText);
|
||||
}
|
||||
if (rightObjs.length !== 0) {
|
||||
// Slice or splice `objects`.
|
||||
refExp = (function() {
|
||||
switch (false) {
|
||||
case !isSplat:
|
||||
return compSplice(objects[expIdx].unwrapAll().value, rightObjs.length * -1);
|
||||
case !isExpans:
|
||||
return compSlice(vvarText, rightObjs.length * -1);
|
||||
}
|
||||
})();
|
||||
if (complexObjects(rightObjs)) {
|
||||
restVar = refExp;
|
||||
refExp = o.scope.freeVariable('ref');
|
||||
assigns.push([this.makeCode(refExp + ' = '), ...restVar.compileToFragments(o, LEVEL_LIST)]);
|
||||
}
|
||||
processObjects(rightObjs, vvar, refExp);
|
||||
}
|
||||
} else {
|
||||
// There is no `Splat` or `Expansion` in `objects`.
|
||||
processObjects(objects, vvar, vvarText);
|
||||
}
|
||||
if (!(top || this.subpattern)) {
|
||||
assigns.push(vvar);
|
||||
@@ -3817,8 +3947,8 @@
|
||||
haveBodyParam = false;
|
||||
// Check for duplicate parameters and separate `this` assignments.
|
||||
paramNames = [];
|
||||
this.eachParamName(function(name, node, param) {
|
||||
var target;
|
||||
this.eachParamName(function(name, node, param, obj) {
|
||||
var replacement, target;
|
||||
if (indexOf.call(paramNames, name) >= 0) {
|
||||
node.error(`multiple parameters named '${name}'`);
|
||||
}
|
||||
@@ -3828,8 +3958,14 @@
|
||||
if (indexOf.call(JS_FORBIDDEN, name) >= 0) {
|
||||
name = `_${name}`;
|
||||
}
|
||||
target = new IdentifierLiteral(o.scope.freeVariable(name));
|
||||
param.renameParam(node, target);
|
||||
target = new IdentifierLiteral(o.scope.freeVariable(name, {
|
||||
reserve: false
|
||||
}));
|
||||
// `Param` is object destructuring with a default value: ({@prop = 1}) ->
|
||||
// In a case when the variable name is already reserved, we have to assign
|
||||
// a new variable name to the destructured variable: ({prop:prop1 = 1}) ->
|
||||
replacement = param.name instanceof Obj && obj instanceof Assign && obj.operatorToken.value === '=' ? new Assign(new IdentifierLiteral(name), target, 'object') : target; //, operatorToken: new Literal ':'
|
||||
param.renameParam(node, replacement);
|
||||
return thisAssignments.push(new Assign(node, target));
|
||||
}
|
||||
});
|
||||
@@ -4156,12 +4292,16 @@
|
||||
var seenSuper;
|
||||
seenSuper = false;
|
||||
context.traverseChildren(true, (child) => {
|
||||
var childArgs;
|
||||
if (child instanceof SuperCall) {
|
||||
// `super` in a constructor (the only `super` without an accessor)
|
||||
// cannot be given an argument with a reference to `this`, as that would
|
||||
// be referencing `this` before calling `super`.
|
||||
if (!child.variable.accessor) {
|
||||
Block.wrap(child.args).traverseChildren(true, (node) => {
|
||||
childArgs = child.args.filter(function(arg) {
|
||||
return !(arg instanceof Class) && (!(arg instanceof Code) || arg.bound);
|
||||
});
|
||||
Block.wrap(childArgs).traverseChildren(true, (node) => {
|
||||
if (node.this) {
|
||||
return node.error("Can't call super with @params in derived class constructors");
|
||||
}
|
||||
@@ -4250,9 +4390,9 @@
|
||||
// `name` is the name of the parameter and `node` is the AST node corresponding
|
||||
// to that name.
|
||||
eachName(iterator, name = this.name) {
|
||||
var atParam, j, len1, node, obj, ref1, ref2;
|
||||
atParam = (obj) => {
|
||||
return iterator(`@${obj.properties[0].name.value}`, obj, this);
|
||||
var atParam, j, len1, nObj, node, obj, ref1, ref2;
|
||||
atParam = (obj, originalObj = null) => {
|
||||
return iterator(`@${obj.properties[0].name.value}`, obj, this, originalObj);
|
||||
};
|
||||
if (name instanceof Literal) {
|
||||
// * simple literals `foo`
|
||||
@@ -4265,6 +4405,8 @@
|
||||
ref2 = (ref1 = name.objects) != null ? ref1 : [];
|
||||
for (j = 0, len1 = ref2.length; j < len1; j++) {
|
||||
obj = ref2[j];
|
||||
// Save original obj.
|
||||
nObj = obj;
|
||||
// * destructured parameter with default value
|
||||
if (obj instanceof Assign && (obj.context == null)) {
|
||||
obj = obj.variable;
|
||||
@@ -4288,7 +4430,7 @@
|
||||
this.eachName(iterator, obj.base);
|
||||
// * at-params within destructured parameters `{@foo}`
|
||||
} else if (obj.this) {
|
||||
atParam(obj);
|
||||
atParam(obj, nObj);
|
||||
} else {
|
||||
// * simple destructured parameters {foo}
|
||||
iterator(obj.base.value, obj.base, this);
|
||||
@@ -4315,7 +4457,15 @@
|
||||
if (node.this) {
|
||||
key = node.properties[0].name;
|
||||
}
|
||||
return new Assign(new Value(key), newNode, 'object');
|
||||
// No need to assign a new variable for the destructured variable if the variable isn't reserved.
|
||||
// Examples:
|
||||
// `({@foo}) ->` should compile to `({foo}) { this.foo = foo}`
|
||||
// `foo = 1; ({@foo}) ->` should compile to `foo = 1; ({foo:foo1}) { this.foo = foo1 }`
|
||||
if (node.this && key.value === newNode.value) {
|
||||
return new Value(newNode);
|
||||
} else {
|
||||
return new Assign(new Value(key), newNode, 'object');
|
||||
}
|
||||
} else {
|
||||
return newNode;
|
||||
}
|
||||
@@ -5288,9 +5438,9 @@
|
||||
// comprehensions. Some of the generated code can be shared in common, and
|
||||
// some cannot.
|
||||
compileNode(o) {
|
||||
var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, fragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref1, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart;
|
||||
var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, down, forPartFragments, fragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref1, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart;
|
||||
body = Block.wrap([this.body]);
|
||||
ref1 = body.expressions, last = ref1[ref1.length - 1];
|
||||
ref1 = body.expressions, [last] = slice1.call(ref1, -1);
|
||||
if ((last != null ? last.jumps() : void 0) instanceof Return) {
|
||||
this.returns = false;
|
||||
}
|
||||
@@ -5397,7 +5547,6 @@
|
||||
if (this.pattern) {
|
||||
body.expressions.unshift(new Assign(this.name, this.from ? new IdentifierLiteral(kvar) : new Literal(`${svar}[${kvar}]`)));
|
||||
}
|
||||
defPartFragments = [].concat(this.makeCode(defPart), this.pluckDirectCall(o, body));
|
||||
if (namePart) {
|
||||
varPart = `\n${idt1}${namePart};`;
|
||||
}
|
||||
@@ -5415,10 +5564,7 @@
|
||||
if (bodyFragments && bodyFragments.length > 0) {
|
||||
bodyFragments = [].concat(this.makeCode('\n'), bodyFragments, this.makeCode('\n'));
|
||||
}
|
||||
fragments = [];
|
||||
if ((defPartFragments != null) && fragmentsToText(defPartFragments) !== '') {
|
||||
fragments = fragments.concat(defPartFragments);
|
||||
}
|
||||
fragments = [this.makeCode(defPart)];
|
||||
if (resultPart) {
|
||||
fragments.push(this.makeCode(resultPart));
|
||||
}
|
||||
@@ -5429,32 +5575,6 @@
|
||||
return fragments;
|
||||
}
|
||||
|
||||
pluckDirectCall(o, body) {
|
||||
var base, defs, expr, fn, idx, j, len1, ref, ref1, ref2, ref3, ref4, ref5, ref6, val;
|
||||
defs = [];
|
||||
ref1 = body.expressions;
|
||||
for (idx = j = 0, len1 = ref1.length; j < len1; idx = ++j) {
|
||||
expr = ref1[idx];
|
||||
expr = expr.unwrapAll();
|
||||
if (!(expr instanceof Call)) {
|
||||
continue;
|
||||
}
|
||||
val = (ref2 = expr.variable) != null ? ref2.unwrapAll() : void 0;
|
||||
if (!((val instanceof Code) || (val instanceof Value && ((ref3 = val.base) != null ? ref3.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((ref4 = (ref5 = val.properties[0].name) != null ? ref5.value : void 0) === 'call' || ref4 === 'apply')))) {
|
||||
continue;
|
||||
}
|
||||
fn = ((ref6 = val.base) != null ? ref6.unwrapAll() : void 0) || val;
|
||||
ref = new IdentifierLiteral(o.scope.freeVariable('fn'));
|
||||
base = new Value(ref);
|
||||
if (val.base) {
|
||||
[val.base, base] = [base, val];
|
||||
}
|
||||
body.expressions[idx] = new Call(base, expr.args);
|
||||
defs = defs.concat(this.makeCode(this.tab), new Assign(ref, fn).compileToFragments(o, LEVEL_TOP), this.makeCode(';\n'));
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
For.prototype.children = ['body', 'source', 'guard', 'step'];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// Generated by CoffeeScript 2.2.1
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
|
||||
slice = [].slice;
|
||||
splice = [].splice;
|
||||
|
||||
({repeat} = require('./helpers'));
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
// `--` argument after, because that will fail on Linux (see #3946).
|
||||
({rules, positional} = normalizeArguments(args, this.rules.flagDict));
|
||||
options = {};
|
||||
// The `argument` field is added to the rule instance non-destructively by
|
||||
// `normalizeArguments`.
|
||||
// The `argument` field is added to the rule instance non-destructively by
|
||||
// `normalizeArguments`.
|
||||
for (i = 0, len = rules.length; i < len; i++) {
|
||||
({hasArgument, argument, isList, name} = rules[i]);
|
||||
if (hasArgument) {
|
||||
@@ -157,7 +157,7 @@
|
||||
};
|
||||
|
||||
normalizeArguments = function(args, flagDict) {
|
||||
var arg, argIndex, flag, i, innerOpts, j, k, lastOpt, len, len1, multiFlags, multiOpts, needsArgOpt, positional, ref, rule, rules, singleRule, withArg;
|
||||
var arg, argIndex, flag, i, innerOpts, j, lastOpt, len, len1, multiFlags, multiOpts, needsArgOpt, positional, ref, rule, rules, singleRule, withArg;
|
||||
rules = [];
|
||||
positional = [];
|
||||
needsArgOpt = null;
|
||||
@@ -187,9 +187,9 @@
|
||||
return {rule, flag};
|
||||
});
|
||||
// Only the last flag in a multi-flag may have an argument.
|
||||
innerOpts = 2 <= multiOpts.length ? slice.call(multiOpts, 0, j = multiOpts.length - 1) : (j = 0, []), lastOpt = multiOpts[j++];
|
||||
for (k = 0, len1 = innerOpts.length; k < len1; k++) {
|
||||
({rule, flag} = innerOpts[k]);
|
||||
[...innerOpts] = multiOpts, [lastOpt] = splice.call(innerOpts, -1);
|
||||
for (j = 0, len1 = innerOpts.length; j < len1; j++) {
|
||||
({rule, flag} = innerOpts[j]);
|
||||
if (rule.hasArgument) {
|
||||
throw new Error(`cannot use option ${flag} in multi-flag ${arg} except as the last option, because it needs an argument`);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// Generated by CoffeeScript 2.2.1
|
||||
(function() {
|
||||
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, getRootModule, helpers, i, len, loadFile, path, ref;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// Generated by CoffeeScript 2.2.1
|
||||
(function() {
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, transpile, updateSyntaxError, vm;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
@@ -218,7 +218,7 @@
|
||||
indexOfTag(i, ...pattern) {
|
||||
var fuzz, j, k, ref, ref1;
|
||||
fuzz = 0;
|
||||
for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) {
|
||||
for (j = k = 0, ref = pattern.length; undefined !== 0 && (0 <= ref ? 0 <= k && k < ref : 0 >= k && k > ref); j = 0 <= ref ? ++k : --k) {
|
||||
if (pattern[j] == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -281,7 +281,7 @@
|
||||
stack = [];
|
||||
start = null;
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
||||
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inControlFlow, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
||||
[tag] = token;
|
||||
[prevTag] = prevToken = i > 0 ? tokens[i - 1] : [];
|
||||
[nextTag] = nextToken = i < tokens.length - 1 ? tokens[i + 1] : [];
|
||||
@@ -420,10 +420,31 @@
|
||||
}
|
||||
start = stack.pop();
|
||||
}
|
||||
inControlFlow = () => {
|
||||
var controlFlow, isFunc, seenFor, tagCurrentLine;
|
||||
seenFor = this.findTagsBackwards(i, ['FOR']) && this.findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM']);
|
||||
controlFlow = seenFor || this.findTagsBackwards(i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']);
|
||||
if (!controlFlow) {
|
||||
return false;
|
||||
}
|
||||
isFunc = false;
|
||||
tagCurrentLine = token[2].first_line;
|
||||
this.detectEnd(i, function(token, i) {
|
||||
var ref;
|
||||
return ref = token[0], indexOf.call(LINEBREAKS, ref) >= 0;
|
||||
}, function(token, i) {
|
||||
var first_line;
|
||||
[prevTag, , {first_line}] = tokens[i - 1] || [];
|
||||
return isFunc = tagCurrentLine === first_line && (prevTag === '->' || prevTag === '=>');
|
||||
}, {
|
||||
returnOnNegativeLevel: true
|
||||
});
|
||||
return isFunc;
|
||||
};
|
||||
// Recognize standard implicit calls like
|
||||
// f a, f() b, f? c, h[0] d etc.
|
||||
// Added support for spread dots on the left side: f ...a
|
||||
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || (nextTag === '...' && (ref = this.tag(i + 2), indexOf.call(IMPLICIT_CALL, ref) >= 0) && !this.findTagsBackwards(i, ['INDEX_START', '['])) || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine)) {
|
||||
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || (nextTag === '...' && (ref = this.tag(i + 2), indexOf.call(IMPLICIT_CALL, ref) >= 0) && !this.findTagsBackwards(i, ['INDEX_START', '['])) || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine) && !inControlFlow()) {
|
||||
if (tag === '?') {
|
||||
tag = token[0] = 'FUNC_EXIST';
|
||||
}
|
||||
@@ -506,11 +527,11 @@
|
||||
}
|
||||
}
|
||||
newLine = prevTag === 'OUTDENT' || prevToken.newLine;
|
||||
if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
|
||||
if (indexOf.call(IMPLICIT_END, tag) >= 0 || (indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) || ((tag === '..' || tag === '...') && this.findTagsBackwards(i, ["INDEX_START"]))) {
|
||||
while (inImplicit()) {
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop();
|
||||
// Close implicit calls when reached end of argument list
|
||||
if (inImplicitCall() && prevTag !== ',') {
|
||||
if (inImplicitCall() && prevTag !== ',' || (prevTag === ',' && tag === 'TERMINATOR' && (nextTag == null))) {
|
||||
endImplicitCall();
|
||||
// Close implicit objects such as:
|
||||
// return a: 1, b: 2 unless true
|
||||
@@ -781,18 +802,51 @@
|
||||
// newlines within expressions are removed and the indentation tokens of empty
|
||||
// blocks are added.
|
||||
normalizeLines() {
|
||||
var action, condition, indent, outdent, starter;
|
||||
var action, closeElseTag, condition, ifThens, indent, leading_if_then, leading_switch_when, outdent, starter;
|
||||
starter = indent = outdent = null;
|
||||
leading_switch_when = null;
|
||||
leading_if_then = null;
|
||||
// Count `THEN` tags
|
||||
ifThens = [];
|
||||
condition = function(token, i) {
|
||||
var ref, ref1, ref2, ref3;
|
||||
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && (this.tokens[i - 1].newLine || this.tokens[i - 1][0] === 'OUTDENT');
|
||||
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && (starter !== 'THEN' || (leading_if_then || leading_switch_when))) && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && (this.tokens[i - 1].newLine || this.tokens[i - 1][0] === 'OUTDENT');
|
||||
};
|
||||
action = function(token, i) {
|
||||
if (token[0] === 'ELSE' && starter === 'THEN') {
|
||||
ifThens.pop();
|
||||
}
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
};
|
||||
closeElseTag = (tokens, i) => {
|
||||
var lastThen, outdentElse, tlen;
|
||||
tlen = ifThens.length;
|
||||
if (!(tlen > 0)) {
|
||||
return i;
|
||||
}
|
||||
lastThen = ifThens.pop();
|
||||
[, outdentElse] = this.indentation(tokens[lastThen]);
|
||||
// Insert `OUTDENT` to close inner `IF`.
|
||||
outdentElse[1] = tlen * 2;
|
||||
tokens.splice(i, 0, outdentElse);
|
||||
// Insert `OUTDENT` to close outer `IF`.
|
||||
outdentElse[1] = 2;
|
||||
tokens.splice(i + 1, 0, outdentElse);
|
||||
// Remove outdents from the end.
|
||||
this.detectEnd(i + 2, function(token, i) {
|
||||
var ref;
|
||||
return (ref = token[0]) === 'OUTDENT' || ref === 'TERMINATOR';
|
||||
}, function(token, i) {
|
||||
if (this.tag(i) === 'OUTDENT' && this.tag(i + 1) === 'OUTDENT') {
|
||||
return tokens.splice(i, 2);
|
||||
}
|
||||
});
|
||||
return i + 2;
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var j, k, ref, ref1, tag;
|
||||
var conditionTag, j, k, ref, ref1, tag;
|
||||
[tag] = token;
|
||||
conditionTag = (tag === '->' || tag === '=>') && this.findTagsBackwards(i, ['IF', 'WHILE', 'FOR', 'UNTIL', 'SWITCH', 'WHEN', 'LEADING_WHEN', '[', 'INDEX_START']) && !(this.findTagsBackwards(i, ['THEN', '..', '...']));
|
||||
if (tag === 'TERMINATOR') {
|
||||
if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
tokens.splice(i, 1, ...this.indentation());
|
||||
@@ -817,12 +871,23 @@
|
||||
tokens.splice(i + 1, 0, indent, outdent);
|
||||
return 1;
|
||||
}
|
||||
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF') && !conditionTag) {
|
||||
starter = tag;
|
||||
[indent, outdent] = this.indentation(tokens[i]);
|
||||
if (starter === 'THEN') {
|
||||
indent.fromThen = true;
|
||||
}
|
||||
if (tag === 'THEN') {
|
||||
leading_switch_when = this.findTagsBackwards(i, ['LEADING_WHEN']) && this.tag(i + 1) === 'IF';
|
||||
leading_if_then = this.findTagsBackwards(i, ['IF']) && this.tag(i + 1) === 'IF';
|
||||
}
|
||||
if (tag === 'THEN' && this.findTagsBackwards(i, ['IF'])) {
|
||||
ifThens.push(i);
|
||||
}
|
||||
// `ELSE` tag is not closed.
|
||||
if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
i = closeElseTag(tokens, i);
|
||||
}
|
||||
tokens.splice(i + 1, 0, indent);
|
||||
this.detectEnd(i + 2, condition, action);
|
||||
if (tag === 'THEN') {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by CoffeeScript 2.1.1
|
||||
// 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
|
||||
|
||||
290
package-lock.json
generated
290
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "coffeescript",
|
||||
"version": "2.1.0",
|
||||
"version": "2.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1281,237 +1281,237 @@
|
||||
}
|
||||
},
|
||||
"babel-preset-minify": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz",
|
||||
"integrity": "sha512-mR8Q44RmMzm18bM2Lqd9uiPopzk5GDCtVuquNbLFmX6lOKnqWoenaNBxnWW0UhBFC75lEHTIgNGCbnsRI0pJVw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.3.0.tgz",
|
||||
"integrity": "sha512-+VV2GWEyak3eDOmzT1DDMuqHrw3VbE9nBNkx2LLVs4pH/Me32ND8DRpVDd8IRvk1xX5p75nygyRPtkMh6GIAbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-plugin-minify-builtins": "0.2.0",
|
||||
"babel-plugin-minify-constant-folding": "0.2.0",
|
||||
"babel-plugin-minify-dead-code-elimination": "0.2.0",
|
||||
"babel-plugin-minify-flip-comparisons": "0.2.0",
|
||||
"babel-plugin-minify-guarded-expressions": "0.2.0",
|
||||
"babel-plugin-minify-infinity": "0.2.0",
|
||||
"babel-plugin-minify-mangle-names": "0.2.0",
|
||||
"babel-plugin-minify-numeric-literals": "0.2.0",
|
||||
"babel-plugin-minify-replace": "0.2.0",
|
||||
"babel-plugin-minify-simplify": "0.2.0",
|
||||
"babel-plugin-minify-type-constructors": "0.2.0",
|
||||
"babel-plugin-transform-inline-consecutive-adds": "0.2.0",
|
||||
"babel-plugin-transform-member-expression-literals": "6.8.5",
|
||||
"babel-plugin-transform-merge-sibling-variables": "6.8.6",
|
||||
"babel-plugin-transform-minify-booleans": "6.8.3",
|
||||
"babel-plugin-transform-property-literals": "6.8.5",
|
||||
"babel-plugin-transform-regexp-constructors": "0.2.0",
|
||||
"babel-plugin-transform-remove-console": "6.8.5",
|
||||
"babel-plugin-transform-remove-debugger": "6.8.5",
|
||||
"babel-plugin-transform-remove-undefined": "0.2.0",
|
||||
"babel-plugin-transform-simplify-comparison-operators": "6.8.5",
|
||||
"babel-plugin-transform-undefined-to-void": "6.8.3",
|
||||
"babel-plugin-minify-builtins": "0.3.0",
|
||||
"babel-plugin-minify-constant-folding": "0.3.0",
|
||||
"babel-plugin-minify-dead-code-elimination": "0.3.0",
|
||||
"babel-plugin-minify-flip-comparisons": "0.3.0",
|
||||
"babel-plugin-minify-guarded-expressions": "0.3.0",
|
||||
"babel-plugin-minify-infinity": "0.3.0",
|
||||
"babel-plugin-minify-mangle-names": "0.3.0",
|
||||
"babel-plugin-minify-numeric-literals": "0.3.0",
|
||||
"babel-plugin-minify-replace": "0.3.0",
|
||||
"babel-plugin-minify-simplify": "0.3.0",
|
||||
"babel-plugin-minify-type-constructors": "0.3.0",
|
||||
"babel-plugin-transform-inline-consecutive-adds": "0.3.0",
|
||||
"babel-plugin-transform-member-expression-literals": "6.9.0",
|
||||
"babel-plugin-transform-merge-sibling-variables": "6.9.0",
|
||||
"babel-plugin-transform-minify-booleans": "6.9.0",
|
||||
"babel-plugin-transform-property-literals": "6.9.0",
|
||||
"babel-plugin-transform-regexp-constructors": "0.3.0",
|
||||
"babel-plugin-transform-remove-console": "6.9.0",
|
||||
"babel-plugin-transform-remove-debugger": "6.9.0",
|
||||
"babel-plugin-transform-remove-undefined": "0.3.0",
|
||||
"babel-plugin-transform-simplify-comparison-operators": "6.9.0",
|
||||
"babel-plugin-transform-undefined-to-void": "6.9.0",
|
||||
"lodash.isplainobject": "4.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-helper-evaluate-path": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz",
|
||||
"integrity": "sha512-0EK9TUKMxHL549hWDPkQoS7R0Ozg1CDLheVBHYds2B2qoAvmr9ejY3zOXFsrICK73TN7bPhU14PBeKc8jcBTwg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.3.0.tgz",
|
||||
"integrity": "sha512-dRFlMTqUJRGzx5a2smKxmptDdNCXKSkPcXWzKLwAV72hvIZumrd/0z9RcewHkr7PmAEq+ETtpD1GK6wZ6ZUXzw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-helper-flip-expressions": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz",
|
||||
"integrity": "sha512-rAsPA1pWBc7e2E6HepkP2e1sXugT+Oq/VCqhyuHJ8aJ2d/ifwnJfd4Qxjm21qlW43AN8tqaeByagKK6wECFMSw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.3.0.tgz",
|
||||
"integrity": "sha512-kNGohWmtAG3b7tN1xocRQ5rsKkH/hpvZsMiGOJ1VwGJKhnwzR5KlB3rvKBaBPl5/IGHcopB2JN+r1SUEX1iMAw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-helper-is-void-0": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz",
|
||||
"integrity": "sha512-Axj1AYuD0E3Dl7nT3KxROP7VekEofz3XtEljzURf3fABalLpr8PamtgLFt+zuxtaCxRf9iuZmbAMMYWri5Bazw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.3.0.tgz",
|
||||
"integrity": "sha512-JVqdX8y7Rf/x4NwbqtUI7mdQjL9HWoDnoAEQ8Gv8oxzjvbJv+n75f7l36m9Y8C7sCUltX3V5edndrp7Hp1oSXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-helper-mark-eval-scopes": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz",
|
||||
"integrity": "sha512-KJuwrOUcHbvbh6he4xRXZFLaivK9DF9o3CrvpWnK1Wp0B+1ANYABXBMgwrnNFIDK/AvicxQ9CNr8wsgivlp4Aw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.3.0.tgz",
|
||||
"integrity": "sha512-nrho5Dg4vl0VUgURVpGpEGiwbst5JX7efIyDHFxmkCx/ocQFnrPt8ze9Kxl6TKjR29bJ7D/XKY1NMlSxOQJRbQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-helper-remove-or-void": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz",
|
||||
"integrity": "sha512-1Z41upf/XR+PwY7Nd+F15Jo5BiQi5205ZXUuKed3yoyQgDkMyoM7vAdjEJS/T+M6jy32sXjskMUgms4zeiVtRA==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.3.0.tgz",
|
||||
"integrity": "sha512-D68W1M3ibCcbg0ysh3ww4/O0g10X1CXK720oOuR8kpfY7w0yP4tVcpK7zDmI1JecynycTQYAZ1rhLJo9aVtIKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-helper-to-multiple-sequence-expressions": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz",
|
||||
"integrity": "sha512-ij9lpfdP3+Zc/7kNwa+NXbTrUlsYEWPwt/ugmQO0qflzLrveTIkbfOqQztvitk81aG5NblYDQXDlRohzu3oa8Q==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.3.0.tgz",
|
||||
"integrity": "sha512-1uCrBD+EAaMnAYh7hc944n8Ga19y3daEnoXWPYDvFVsxMCc1l8aDjksApaCEaNSSuewq8BEcff47Cy1PbLg2Gw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-minify-builtins": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz",
|
||||
"integrity": "sha512-4i+8ntaS8gwVUcOz5y+zE+55OVOl2nTbmHV51D4wAIiKcRI8U5K//ip1GHfhsgk/NJrrHK7h97Oy5jpqt0Iixg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.3.0.tgz",
|
||||
"integrity": "sha512-MqhSHlxkmgURqj3144qPksbZ/qof1JWdumcbucc4tysFcf3P3V3z3munTevQgKEFNMd8F5/ECGnwb63xogLjAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-evaluate-path": "0.2.0"
|
||||
"babel-helper-evaluate-path": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-constant-folding": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz",
|
||||
"integrity": "sha512-B3ffQBEUQ8ydlIkYv2MkZtTCbV7FAkWAV7NkyhcXlGpD10PaCxNGQ/B9oguXGowR1m16Q5nGhvNn8Pkn1MO6Hw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.3.0.tgz",
|
||||
"integrity": "sha512-1XeRpx+aY1BuNY6QU/cm6P+FtEi3ar3XceYbmC+4q4W+2Ewq5pL7V68oHg1hKXkBIE0Z4/FjSoHz6vosZLOe/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-evaluate-path": "0.2.0"
|
||||
"babel-helper-evaluate-path": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-dead-code-elimination": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz",
|
||||
"integrity": "sha512-zE7y3pRyzA4zK5nBou0kTcwUTSQ/AiFrynt1cIEYN7vcO2gS9ZFZoI0aO9JYLUdct5fsC1vfB35408yrzTyVfg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.3.0.tgz",
|
||||
"integrity": "sha512-SjM2Fzg85YZz+q/PNJ/HU4O3W98FKFOiP9K5z3sfonlamGOzvZw3Eup2OTiEBsbbqTeY8yzNCAv3qpJRYCgGmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-evaluate-path": "0.2.0",
|
||||
"babel-helper-mark-eval-scopes": "0.2.0",
|
||||
"babel-helper-remove-or-void": "0.2.0",
|
||||
"babel-helper-evaluate-path": "0.3.0",
|
||||
"babel-helper-mark-eval-scopes": "0.3.0",
|
||||
"babel-helper-remove-or-void": "0.3.0",
|
||||
"lodash.some": "4.6.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-flip-comparisons": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz",
|
||||
"integrity": "sha512-QOqXSEmD/LhT3LpM1WCyzAGcQZYYKJF7oOHvS6QbpomHenydrV53DMdPX2mK01icBExKZcJAHF209wvDBa+CSg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.3.0.tgz",
|
||||
"integrity": "sha512-B8lK+ekcpSNVH7PZpWDe5nC5zxjRiiT4nTsa6h3QkF3Kk6y9qooIFLemdGlqBq6j0zALEnebvCpw8v7gAdpgnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-is-void-0": "0.2.0"
|
||||
"babel-helper-is-void-0": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-guarded-expressions": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz",
|
||||
"integrity": "sha512-5+NSPdRQ9mnrHaA+zFj+D5OzmSiv90EX5zGH6cWQgR/OUqmCHSDqgTRPFvOctgpo8MJyO7Rt7ajs2UfLnlAwYg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.3.0.tgz",
|
||||
"integrity": "sha512-O+6CvF5/Ttsth3LMg4/BhyvVZ82GImeKMXGdVRQGK/8jFiP15EjRpdgFlxv3cnqRjqdYxLCS6r28VfLpb9C/kA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-flip-expressions": "0.2.0"
|
||||
"babel-helper-flip-expressions": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-infinity": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz",
|
||||
"integrity": "sha512-U694vrla1lN6vDHWGrR832t3a/A2eh+kyl019LxEE2+sS4VTydyOPRsAOIYAdJegWRA4cMX1lm9azAN0cLIr8g==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.3.0.tgz",
|
||||
"integrity": "sha512-Sj8ia3/w9158DWieUxU6/VvnYVy59geeFEkVgLZYBE8EBP+sN48tHtBM/jSgz0ejEdBlcfqJ6TnvPmVXTzR2BQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-minify-mangle-names": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz",
|
||||
"integrity": "sha512-Gixuak1/CO7VCdjn15/8Bxe/QsAtDG4zPbnsNoe1mIJGCIH/kcmSjFhMlGJtXDQZd6EKzeMfA5WmX9+jvGRefw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.3.0.tgz",
|
||||
"integrity": "sha512-PYTonhFWURsfAN8achDwvR5Xgy6EeTClLz+fSgGRqjAIXb0OyFm3/xfccbQviVi1qDXmlSnt6oJhBg8KE4Fn7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-mark-eval-scopes": "0.2.0"
|
||||
"babel-helper-mark-eval-scopes": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-numeric-literals": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz",
|
||||
"integrity": "sha512-VcLpb+r1YS7+RIOXdRsFVLLqoh22177USpHf+JM/g1nZbzdqENmfd5v534MLAbRErhbz6SyK+NQViVzVtBxu8g==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.3.0.tgz",
|
||||
"integrity": "sha512-TgZj6ay8zDw74AS3yiIfoQ8vRSNJisYO/Du60S8nPV7EW7JM6fDMx5Sar6yVHlVuuwNgvDUBh191K33bVrAhpg==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-minify-replace": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz",
|
||||
"integrity": "sha512-SEW6zoSVxh3OH6E1LCgyhhTWMnCv+JIRu5h5IlJDA11tU4ZeSF7uPQcO4vN/o52+FssRB26dmzJ/8D+z0QPg5Q==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.3.0.tgz",
|
||||
"integrity": "sha512-VR6tTg2Lt0TicHIOw04fsUtpPw7RaRP8PC8YzSFwEixnzvguZjZJoL7TgG7ZyEWQD1cJ96UezswECmFNa815bg==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-minify-simplify": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz",
|
||||
"integrity": "sha512-Mj3Mwy2zVosMfXDWXZrQH5/uMAyfJdmDQ1NVqit+ArbHC3LlXVzptuyC1JxTyai/wgFvjLaichm/7vSUshkWqw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.3.0.tgz",
|
||||
"integrity": "sha512-2M16ytQOCqBi7bYMu4DCWn8e6KyFCA108F6+tVrBJxOmm5u2sOmTFEa8s94tR9RHRRNYmcUf+rgidfnzL3ik9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-flip-expressions": "0.2.0",
|
||||
"babel-helper-flip-expressions": "0.3.0",
|
||||
"babel-helper-is-nodes-equiv": "0.0.1",
|
||||
"babel-helper-to-multiple-sequence-expressions": "0.2.0"
|
||||
"babel-helper-to-multiple-sequence-expressions": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-minify-type-constructors": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz",
|
||||
"integrity": "sha512-NiOvvA9Pq6bki6nP4BayXwT5GZadw7DJFDDzHmkpnOQpENWe8RtHtKZM44MG1R6EQ5XxgbLdsdhswIzTkFlO5g==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.3.0.tgz",
|
||||
"integrity": "sha512-XRXpvsUCPeVw9YEUw+9vSiugcSZfow81oIJT0yR9s8H4W7yJ6FHbImi5DJHoL8KcDUjYnL9wYASXk/fOkbyR6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-is-void-0": "0.2.0"
|
||||
"babel-helper-is-void-0": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-inline-consecutive-adds": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz",
|
||||
"integrity": "sha512-GlhOuLOQ28ua9prg0hT33HslCrEmz9xWXy9ZNZSACppCyRxxRW+haYtRgm7uYXCcd0q8ggCWD2pfWEJp5iiZfQ==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.3.0.tgz",
|
||||
"integrity": "sha512-iZsYAIjYLLfLK0yN5WVT7Xf7Y3wQ9Z75j9A8q/0IglQSpUt2ppTdHlwl/GeaXnxdaSmsxBu861klbTBbv2n+RA==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-member-expression-literals": {
|
||||
"version": "6.8.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz",
|
||||
"integrity": "sha512-Ux3ligf+ukzWaCbBYOstDuFBhRgMiJHlpJBKV4P47qtzVkd0lg1ddPj9fqIJqAM0n+CvxipyrZrnNnw3CdtQCg==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.0.tgz",
|
||||
"integrity": "sha512-bxtac+8w755ctVeDs4vU98RhWY49eW1wO02HAN+eirZYSKk/dVrKONIznXbHmxWKxT4UX1rpTKOCyezuzLpbTw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-merge-sibling-variables": {
|
||||
"version": "6.8.6",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz",
|
||||
"integrity": "sha512-o5Jioq553HtEAUN5uty7ELJMenXIxHI3PIs1yLqYWYQwP6mg6IPVAJ+U7i4zr9XGF/kb2RGsdehglGTV+vngqA==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.0.tgz",
|
||||
"integrity": "sha512-9G1URVEEKoQLDqe0GwqYudECN7kE/q0OCNo5TiD1iwWnnaKi97xY915l5r2KKUvNflXEm9c3faNWknSXYQ7h6Q==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-minify-booleans": {
|
||||
"version": "6.8.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz",
|
||||
"integrity": "sha512-bPbUhkeN2Nc0KH0/A19GwQGj8w+CvdJzyu8t59VoEDgsNMQ9Bopzi5DrVkrSsVjbYUaZpzq/DYLrH+wD5K2Tig==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.0.tgz",
|
||||
"integrity": "sha512-JtpyTRyF+wF/r7GSxpRbNCrVve5M/aCC8xoGcnFItaPUDqjxKmFYvBzMc9u+g0lgo8NWjuZLc16MYaIwkHKD/A==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-property-literals": {
|
||||
"version": "6.8.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz",
|
||||
"integrity": "sha512-MmiQsQ5AcIaRZMJD0zY5C4H3xuHm06/nWgtOsz7AXV44VEIXIlPiJ39IFYJ4Qx67/fEm8zJAedzR8t+B7d10Bg==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.0.tgz",
|
||||
"integrity": "sha512-B8s+71+4DPye9+pmZiPGgLPy3YqcmIuvE/9UcZLczPlwL5ALwF6qRUdLC3Fk17NhL6jxp4u33ZVZ8R4kvASPzw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esutils": "2.0.2"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-regexp-constructors": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz",
|
||||
"integrity": "sha512-7IsQ6aQx6LAaOqy97/PthTf+5Nx9grZww3r6E62IdWe76Yr8KsuwVjxzqSPQvESJqTE3EMADQ9S0RtwWDGNG9Q==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.3.0.tgz",
|
||||
"integrity": "sha512-h92YHzyl042rb0naKO8frTHntpRFwRgKkfWD8602kFHoQingjJNtbvZzvxqHncJ6XmKVyYvfrBpDOSkCTDIIxw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-remove-console": {
|
||||
"version": "6.8.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz",
|
||||
"integrity": "sha512-uuCKvtweCyIvvC8fi92EcWRtO2Kt5KMNMRK6BhpDXdeb3sxvGM7453RSmgeu4DlKns3OlvY9Ep5Q9m5a7RQAgg==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.0.tgz",
|
||||
"integrity": "sha512-mck9//yGTwObqqqDzY/sISO88/5/XfIB3ILb4uJLXk2xq124NT4yQVjFSRgVSbLcNq8OyBAn2acxKUqg4W/okQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-remove-debugger": {
|
||||
"version": "6.8.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz",
|
||||
"integrity": "sha512-InDQDdHPOLJKM+G6oXrEesf+P29QFBmcTXID+TAvZziVz+38xe2VO/Bn3FcRcRtnOOycbgsJkUNp9jIK+ist6g==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.0.tgz",
|
||||
"integrity": "sha512-i/HWGjsmL2d1N2dl+eIzf44XpSP5v7hi1/GXB0xzom9kjrU8js3T8Kadizn95ZxfHK592Vg8P4JJWP/fvimEWw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-remove-undefined": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz",
|
||||
"integrity": "sha512-O8v57tPMHkp89kA4ZfQEYds/pzgvz/QYerBJjIuL5/Jc7RnvMVRA5gJY9zFKP7WayW8WOSBV4vh8Y8FJRio+ow==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.3.0.tgz",
|
||||
"integrity": "sha512-TYGQucc8iP3LJwN3kDZLEz5aa/2KuFrqpT+s8f8NnHsBU1sAgR3y8Opns0xhC+smyDYWscqFCKM1gbkWQOhhnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-evaluate-path": "0.2.0"
|
||||
"babel-helper-evaluate-path": "0.3.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-simplify-comparison-operators": {
|
||||
"version": "6.8.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz",
|
||||
"integrity": "sha512-B3HlBZb+Uq86nRj5yNPO6pJ3noEdqHvzYkEYoUWtrsWTv48ZIRatYlumoOiif/v8llF13YjYjx9zhyznDx+N9g==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.0.tgz",
|
||||
"integrity": "sha512-EJyfYeph0CSekwQuwWVwJqy2go/bETkR95iaWQ/HTUis7tkCGNYmXngaFzuIXdmoPXfvmXYCvAXR4/93hqHVjw==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-transform-undefined-to-void": {
|
||||
"version": "6.8.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz",
|
||||
"integrity": "sha512-goYwp8dMrzHD6x9GjZ2M85Mk2vxf1h85CnUgAjfftUnlJvzF4uj5MrbReHBTbjQ96C8CuRzvhYZ3tv8H3Sc1ZA==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.0.tgz",
|
||||
"integrity": "sha512-AVDVEmp0S9mbF1O8zekWbsOOmqnR08PZah5NRZJqSvJnFgiL0ep4Lwo4EymH8OieJR2QgQdR3q71TNW+wiVn4g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -1847,9 +1847,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
||||
"version": "2.13.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
|
||||
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
@@ -2018,15 +2018,15 @@
|
||||
}
|
||||
},
|
||||
"docco": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/docco/-/docco-0.7.0.tgz",
|
||||
"integrity": "sha1-1gblqZDLoFLKHhgDqcWH7O48XDg=",
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/docco/-/docco-0.8.0.tgz",
|
||||
"integrity": "sha512-QcWBDnnGaT+rgC0wqynznXv0/4hd6nAFdWNs2fN4FvkH2yAnCYVeRU7GIZXNCeUQ955Lufq+TmZcSXiBa1cGQQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "2.11.0",
|
||||
"fs-extra": "3.0.1",
|
||||
"commander": "2.13.0",
|
||||
"fs-extra": "5.0.0",
|
||||
"highlight.js": "9.12.0",
|
||||
"marked": "0.3.6",
|
||||
"marked": "0.3.12",
|
||||
"underscore": "1.8.3"
|
||||
}
|
||||
},
|
||||
@@ -2391,14 +2391,14 @@
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz",
|
||||
"integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"jsonfile": "3.0.1",
|
||||
"universalify": "0.1.0"
|
||||
"jsonfile": "4.0.0",
|
||||
"universalify": "0.1.1"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
@@ -3649,9 +3649,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz",
|
||||
"integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11"
|
||||
@@ -3802,9 +3802,9 @@
|
||||
}
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz",
|
||||
"integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=",
|
||||
"version": "0.3.12",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz",
|
||||
"integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==",
|
||||
"dev": true
|
||||
},
|
||||
"md5.js": {
|
||||
@@ -4784,9 +4784,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.0.tgz",
|
||||
"integrity": "sha1-nrHEZR3rzGcMyU8adXYjMruWd3g=",
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
|
||||
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=",
|
||||
"dev": true
|
||||
},
|
||||
"url": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"compiler"
|
||||
],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.1",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -42,9 +42,9 @@
|
||||
"babel-core": "~6.26.0",
|
||||
"babel-preset-babili": "~0.1.4",
|
||||
"babel-preset-env": "~1.6.1",
|
||||
"babel-preset-minify": "^0.2.0",
|
||||
"babel-preset-minify": "^0.3.0",
|
||||
"codemirror": "^5.32.0",
|
||||
"docco": "~0.7.0",
|
||||
"docco": "~0.8.0",
|
||||
"highlight.js": "~9.12.0",
|
||||
"jison": ">=0.4.18",
|
||||
"markdown-it": "~8.4.0",
|
||||
|
||||
@@ -89,6 +89,7 @@ grammar =
|
||||
# grammar.
|
||||
Line: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'Statement'
|
||||
o 'FuncDirective'
|
||||
]
|
||||
@@ -125,6 +126,15 @@ grammar =
|
||||
o 'Yield'
|
||||
]
|
||||
|
||||
# Expressions which are written in single line and would otherwise require being
|
||||
# wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`,
|
||||
# `for x in do (obj) -> f obj when x > 8 then f x`
|
||||
ExpressionLine: [
|
||||
o 'CodeLine'
|
||||
o 'IfLine'
|
||||
o 'OperationLine'
|
||||
]
|
||||
|
||||
Yield: [
|
||||
o 'YIELD', -> new Op $1, new Value new Literal ''
|
||||
o 'YIELD Expression', -> new Op $1, $2
|
||||
@@ -267,6 +277,13 @@ grammar =
|
||||
o 'FuncGlyph Block', -> new Code [], $2, $1
|
||||
]
|
||||
|
||||
# The Codeline is the **Code** node with **Line** instead of indented **Block**.
|
||||
CodeLine: [
|
||||
o 'PARAM_START ParamList PARAM_END FuncGlyph Line', -> new Code $2, LOC(5)(Block.wrap [$5]), $4,
|
||||
LOC(1)(new Literal $1)
|
||||
o 'FuncGlyph Line', -> new Code [], LOC(2)(Block.wrap [$2]), $1
|
||||
]
|
||||
|
||||
# CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
# functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [
|
||||
@@ -506,13 +523,16 @@ grammar =
|
||||
|
||||
# The CoffeeScript range literal.
|
||||
Range: [
|
||||
o '[ Expression RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
o '[ Expression RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
o '[ ExpressionLine RangeDots Expression ]', -> new Range $2, $4, $3
|
||||
]
|
||||
|
||||
# Array slice literals.
|
||||
Slice: [
|
||||
o 'Expression RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'Expression RangeDots', -> new Range $1, null, $2
|
||||
o 'ExpressionLine RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'ExpressionLine RangeDots', -> new Range $1, null, $2
|
||||
o 'RangeDots Expression', -> new Range null, $2, $1
|
||||
o 'RangeDots', -> new Range null, null, $1
|
||||
]
|
||||
@@ -530,6 +550,7 @@ grammar =
|
||||
# Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'Splat'
|
||||
o '...', -> new Expansion
|
||||
]
|
||||
@@ -568,7 +589,9 @@ grammar =
|
||||
# having the newlines wouldn't make sense.
|
||||
SimpleArgs: [
|
||||
o 'Expression'
|
||||
o 'ExpressionLine'
|
||||
o 'SimpleArgs , Expression', -> [].concat $1, $3
|
||||
o 'SimpleArgs , ExpressionLine', -> [].concat $1, $3
|
||||
]
|
||||
|
||||
# The variants of *try/catch/finally* exception handling blocks.
|
||||
@@ -602,17 +625,27 @@ grammar =
|
||||
]
|
||||
|
||||
# The condition portion of a while loop.
|
||||
WhileLineSource: [
|
||||
o 'WHILE ExpressionLine', -> new While $2
|
||||
o 'WHILE ExpressionLine WHEN ExpressionLine', -> new While $2, guard: $4
|
||||
o 'UNTIL ExpressionLine', -> new While $2, invert: true
|
||||
o 'UNTIL ExpressionLine WHEN ExpressionLine', -> new While $2, invert: true, guard: $4
|
||||
]
|
||||
|
||||
WhileSource: [
|
||||
o 'WHILE Expression', -> new While $2
|
||||
o 'WHILE Expression WHEN Expression', -> new While $2, guard: $4
|
||||
o 'WHILE ExpressionLine WHEN Expression', -> new While $2, guard: $4
|
||||
o 'UNTIL Expression', -> new While $2, invert: true
|
||||
o 'UNTIL Expression WHEN Expression', -> new While $2, invert: true, guard: $4
|
||||
o 'UNTIL ExpressionLine WHEN Expression', -> new While $2, invert: true, guard: $4
|
||||
]
|
||||
|
||||
# The while loop can either be normal, with a block of expressions to execute,
|
||||
# or postfix, with a single expression. There is no do..while.
|
||||
While: [
|
||||
o 'WhileSource Block', -> $1.addBody $2
|
||||
o 'WhileLineSource Block', -> $1.addBody $2
|
||||
o 'Statement WhileSource', -> $2.addBody LOC(1) Block.wrap([$1])
|
||||
o 'Expression WhileSource', -> $2.addBody LOC(1) Block.wrap([$1])
|
||||
o 'Loop', -> $1
|
||||
@@ -630,6 +663,7 @@ grammar =
|
||||
o 'Statement ForBody', -> new For $1, $2
|
||||
o 'Expression ForBody', -> new For $1, $2
|
||||
o 'ForBody Block', -> new For $2, $1
|
||||
o 'ForLineBody Block', -> new For $2, $1
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
@@ -638,6 +672,11 @@ grammar =
|
||||
o 'ForStart ForSource', -> $2.own = $1.own; $2.ownTag = $1.ownTag; $2.name = $1[0]; $2.index = $1[1]; $2
|
||||
]
|
||||
|
||||
ForLineBody: [
|
||||
o 'FOR Range BY ExpressionLine', -> source: (LOC(2) new Value($2)), step: $4
|
||||
o 'ForStart ForLineSource', -> $2.own = $1.own; $2.ownTag = $1.ownTag; $2.name = $1[0]; $2.index = $1[1]; $2
|
||||
]
|
||||
|
||||
ForStart: [
|
||||
o 'FOR ForVariables', -> $2
|
||||
o 'FOR OWN ForVariables', -> $3.own = yes; $3.ownTag = (LOC(2) new Literal($2)); $3
|
||||
@@ -664,22 +703,56 @@ grammar =
|
||||
# clause. If it's an array comprehension, you can also choose to step through
|
||||
# in fixed-size increments.
|
||||
ForSource: [
|
||||
o 'FORIN Expression', -> source: $2
|
||||
o 'FOROF Expression', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM Expression', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
o 'FORIN Expression', -> source: $2
|
||||
o 'FOROF Expression', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FORIN ExpressionLine WHEN Expression', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FOROF ExpressionLine WHEN Expression', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN ExpressionLine BY Expression', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN Expression BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM Expression', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
o 'FORFROM ExpressionLine WHEN Expression', -> source: $2, guard: $4, from: yes
|
||||
]
|
||||
|
||||
ForLineSource: [
|
||||
o 'FORIN ExpressionLine', -> source: $2
|
||||
o 'FOROF ExpressionLine', -> source: $2, object: yes
|
||||
o 'FORIN Expression WHEN ExpressionLine', -> source: $2, guard: $4
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4
|
||||
o 'FOROF Expression WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
|
||||
o 'FOROF ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
|
||||
o 'FORIN Expression BY ExpressionLine', -> source: $2, step: $4
|
||||
o 'FORIN ExpressionLine BY ExpressionLine', -> source: $2, step: $4
|
||||
o 'FORIN Expression WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
|
||||
o 'FORIN Expression BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN Expression BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
|
||||
o 'FORFROM ExpressionLine', -> source: $2, from: yes
|
||||
o 'FORFROM Expression WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
|
||||
o 'FORFROM ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
|
||||
]
|
||||
|
||||
Switch: [
|
||||
o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3
|
||||
o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, $5
|
||||
o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH ExpressionLine INDENT Whens OUTDENT', -> new Switch $2, $4
|
||||
o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
|
||||
o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3
|
||||
o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, $5
|
||||
]
|
||||
|
||||
Whens: [
|
||||
@@ -710,12 +783,28 @@ grammar =
|
||||
o 'Expression POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
IfBlockLine: [
|
||||
o 'IF ExpressionLine Block', -> new If $2, $3, type: $1
|
||||
o 'IfBlockLine ELSE IF ExpressionLine Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3
|
||||
]
|
||||
|
||||
IfLine: [
|
||||
o 'IfBlockLine'
|
||||
o 'IfBlockLine ELSE Block', -> $1.addElse $3
|
||||
o 'Statement POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
o 'Expression POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
# Here they are grouped by order of precedence. The actual precedence rules
|
||||
# are defined at the bottom of the page. It would be shorter if we could
|
||||
# combine most of these rules into a single generic *Operand OpSymbol Operand*
|
||||
# -type rule, but in order to make the precedence binding possible, separate
|
||||
# rules are necessary.
|
||||
OperationLine: [
|
||||
o 'UNARY ExpressionLine', -> new Op $1, $2
|
||||
]
|
||||
|
||||
Operation: [
|
||||
o 'UNARY Expression', -> new Op $1 , $2
|
||||
o 'UNARY_MATH Expression', -> new Op $1 , $2
|
||||
|
||||
@@ -192,13 +192,17 @@ exports.Lexer = class Lexer
|
||||
# what CoffeeScript would normally interpret as calls to functions named
|
||||
# `get` or `set`, i.e. `get({foo: function () {}})`.
|
||||
else if tag is 'PROPERTY' and prev
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1]) and @tokens[@tokens.length - 2][0] isnt '.'
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]
|
||||
else
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1]) and
|
||||
@tokens.length > 1 and @tokens[@tokens.length - 2][0] not in ['.', '?.', '@']
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call
|
||||
without parentheses", prev[2]
|
||||
else if @tokens.length > 2
|
||||
prevprev = @tokens[@tokens.length - 2]
|
||||
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and /^[gs]et$/.test(prevprev[1]) and
|
||||
@tokens[@tokens.length - 3][0] isnt '.'
|
||||
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses", prevprev[2]
|
||||
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and
|
||||
/^[gs]et$/.test(prevprev[1]) and
|
||||
@tokens[@tokens.length - 3][0] not in ['.', '?.', '@']
|
||||
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a
|
||||
function call without parentheses", prevprev[2]
|
||||
|
||||
if tag is 'IDENTIFIER' and id in RESERVED
|
||||
@error "reserved word '#{id}'", length: id.length
|
||||
@@ -449,7 +453,9 @@ exports.Lexer = class Lexer
|
||||
return 0 unless match = MULTI_DENT.exec chunk
|
||||
indent = match[0]
|
||||
|
||||
@seenFor = no
|
||||
prev = @prev()
|
||||
backslash = prev? and prev[0] is '\\'
|
||||
@seenFor = no unless backslash and @seenFor
|
||||
@seenImport = no unless @importSpecifierList
|
||||
@seenExport = no unless @exportSpecifierList
|
||||
|
||||
|
||||
364
src/nodes.coffee
364
src/nodes.coffee
@@ -863,6 +863,11 @@ exports.Value = class Value extends Base
|
||||
constructor: (base, props, tag, isDefaultValue = no) ->
|
||||
super()
|
||||
return base if not props and base instanceof Value
|
||||
# When `Parens` block includes a `StatementLiteral` (e.g. `(b; break) for a in arr`),
|
||||
# it won't compile since `Parens` (`(b; break)`) is compiled as `Value` and
|
||||
# pure statement (`break`) can't be used in an expression.
|
||||
# For this reasons, we return `Block` instead of `Parens`.
|
||||
return base.unwrap() if base instanceof Parens and base.contains (n) -> n instanceof StatementLiteral
|
||||
@base = base
|
||||
@properties = props or []
|
||||
@[tag] = yes if tag
|
||||
@@ -956,11 +961,21 @@ exports.Value = class Value extends Base
|
||||
compileNode: (o) ->
|
||||
@base.front = @front
|
||||
props = @properties
|
||||
fragments = @base.compileToFragments o, (if props.length then LEVEL_ACCESS else null)
|
||||
if props.length and @base.cached?
|
||||
# Cached fragments enable correct order of the compilation,
|
||||
# and reuse of variables in the scope.
|
||||
# Example:
|
||||
# `a(x = 5).b(-> x = 6)` should compile in the same order as
|
||||
# `a(x = 5); b(-> x = 6)`
|
||||
# (see issue #4437, https://github.com/jashkenas/coffeescript/issues/4437)
|
||||
fragments = @base.cached
|
||||
else
|
||||
fragments = @base.compileToFragments o, (if props.length then LEVEL_ACCESS else null)
|
||||
if props.length and SIMPLENUM.test fragmentsToText fragments
|
||||
fragments.push @makeCode '.'
|
||||
for prop in props
|
||||
fragments.push (prop.compileToFragments o)...
|
||||
|
||||
fragments
|
||||
|
||||
# Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
|
||||
@@ -1120,6 +1135,19 @@ exports.Call = class Call extends Base
|
||||
return @compileCSX o if @csx
|
||||
@variable?.front = @front
|
||||
compiledArgs = []
|
||||
# If variable is `Accessor` fragments are cached and used later
|
||||
# in `Value::compileNode` to ensure correct order of the compilation,
|
||||
# and reuse of variables in the scope.
|
||||
# Example:
|
||||
# `a(x = 5).b(-> x = 6)` should compile in the same order as
|
||||
# `a(x = 5); b(-> x = 6)`
|
||||
# (see issue #4437, https://github.com/jashkenas/coffeescript/issues/4437)
|
||||
varAccess = @variable?.properties?[0] instanceof Access
|
||||
argCode = (arg for arg in (@args || []) when arg instanceof Code)
|
||||
if argCode.length > 0 and varAccess and not @variable.base.cached
|
||||
[cache] = @variable.base.cache o, LEVEL_ACCESS, -> no
|
||||
@variable.base.cached = cache
|
||||
|
||||
for arg, argIndex in @args
|
||||
if argIndex then compiledArgs.push @makeCode ", "
|
||||
compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
|
||||
@@ -1325,20 +1353,37 @@ 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}"]
|
||||
|
||||
# Generate the condition.
|
||||
condPart = if @stepNum?
|
||||
if @stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}"
|
||||
else if known
|
||||
[from, to] = [@fromNum, @toNum]
|
||||
if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
|
||||
else
|
||||
cond = if @stepVar then "#{@stepVar} > 0" else "#{@fromVar} <= #{@toVar}"
|
||||
"#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}"
|
||||
[from, to] = [@fromNum, @toNum]
|
||||
# Always check if the `step` isn't zero to avoid the infinite loop.
|
||||
stepCond = if @stepNum then "#{@stepNum} !== 0" else "#{@stepVar} !== 0"
|
||||
condPart =
|
||||
if known
|
||||
unless @step?
|
||||
if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
|
||||
else
|
||||
# from < to
|
||||
lowerBound = "#{from} <= #{idx} && #{lt} #{to}"
|
||||
# from > to
|
||||
upperBound = "#{from} >= #{idx} && #{gt} #{to}"
|
||||
if from <= to then "#{stepCond} && #{lowerBound}" else "#{stepCond} && #{upperBound}"
|
||||
else
|
||||
# from < to
|
||||
lowerBound = "#{@fromVar} <= #{idx} && #{lt} #{@toVar}"
|
||||
# from > to
|
||||
upperBound = "#{@fromVar} >= #{idx} && #{gt} #{@toVar}"
|
||||
"#{stepCond} && (#{@fromVar} <= #{@toVar} ? #{lowerBound} : #{upperBound})"
|
||||
|
||||
cond = if @stepVar then "#{@stepVar} > 0" else "#{@fromVar} <= #{@toVar}"
|
||||
|
||||
# Generate the step.
|
||||
stepPart = if @stepVar
|
||||
@@ -1369,9 +1414,9 @@ exports.Range = class Range extends Base
|
||||
range.pop() if @exclusive
|
||||
return [@makeCode "[#{ range.join(', ') }]"]
|
||||
idt = @tab + TAB
|
||||
i = o.scope.freeVariable 'i', single: true
|
||||
result = o.scope.freeVariable 'results'
|
||||
pre = "\n#{idt}#{result} = [];"
|
||||
i = o.scope.freeVariable 'i', single: true, reserve: no
|
||||
result = o.scope.freeVariable 'results', reserve: no
|
||||
pre = "\n#{idt}var #{result} = [];"
|
||||
if known
|
||||
o.index = i
|
||||
body = fragmentsToText @compileNode o
|
||||
@@ -1401,8 +1446,12 @@ exports.Slice = class Slice extends Base
|
||||
# `9e9` should be safe because `9e9` > `2**32`, the max array length.
|
||||
compileNode: (o) ->
|
||||
{to, from} = @range
|
||||
fromCompiled = from and from.compileToFragments(o, LEVEL_PAREN) or [@makeCode '0']
|
||||
# TODO: jwalton - move this into the 'if'?
|
||||
# Handle an expression in the property access, e.g. `a[!b in c..]`.
|
||||
if from?.shouldCache()
|
||||
from = new Value new Parens from
|
||||
if to?.shouldCache()
|
||||
to = new Value new Parens to
|
||||
fromCompiled = from?.compileToFragments(o, LEVEL_PAREN) or [@makeCode '0']
|
||||
if to
|
||||
compiled = to.compileToFragments o, LEVEL_PAREN
|
||||
compiledText = fragmentsToText compiled
|
||||
@@ -2351,47 +2400,26 @@ exports.Assign = class Assign extends Base
|
||||
if olen is 1 and obj instanceof Expansion
|
||||
obj.error 'Destructuring assignment has no target'
|
||||
|
||||
isObject = @variable.isObject()
|
||||
# Count all `Splats`: [a, b, c..., d, e]
|
||||
splats = (i for obj, i in objects when obj instanceof Splat)
|
||||
# Count all `Expansions`: [a, b, ..., c, d]
|
||||
expans = (i for obj, i in objects when obj instanceof Expansion)
|
||||
# Combine splats and expansions.
|
||||
splatsAndExpans = [splats..., expans...]
|
||||
# Show error if there is more than one `Splat`, or `Expansion`.
|
||||
# Examples: [a, b, c..., d, e, f...], [a, b, ..., c, d, ...], [a, b, ..., c, d, e...]
|
||||
if splatsAndExpans.length > 1
|
||||
# Sort 'splatsAndExpans' so we can show error at first disallowed token.
|
||||
objects[splatsAndExpans.sort()[1]].error "multiple splats/expansions are disallowed in an assignment"
|
||||
|
||||
# Special case for when there's only one thing destructured off of
|
||||
# something. `{a} = b`, `[a] = b`, `{a: b} = c`
|
||||
if top and olen is 1 and obj not instanceof Splat
|
||||
# Pick the property straight off the value when there’s just one to pick
|
||||
# (no need to cache the value into a variable).
|
||||
defaultValue = undefined
|
||||
if obj instanceof Assign and obj.context is 'object'
|
||||
# A regular object pattern-match.
|
||||
{variable: {base: idx}, value: obj} = obj
|
||||
if obj instanceof Assign
|
||||
defaultValue = obj.value
|
||||
obj = obj.variable
|
||||
else
|
||||
if obj instanceof Assign
|
||||
defaultValue = obj.value
|
||||
obj = obj.variable
|
||||
idx = if isObject
|
||||
# A shorthand `{a, b, @c} = val` pattern-match.
|
||||
if obj.this
|
||||
obj.properties[0].name
|
||||
else
|
||||
new PropertyName obj.unwrap().value
|
||||
else
|
||||
# A regular array pattern-match.
|
||||
new NumberLiteral 0
|
||||
acc = idx.unwrap() instanceof PropertyName
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
message = isUnassignable obj.unwrap().value
|
||||
obj.error message if message
|
||||
if defaultValue
|
||||
defaultValue.isDefaultValue = yes
|
||||
value = new Op '?', value, defaultValue
|
||||
return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
|
||||
isSplat = splats?.length > 0
|
||||
isExpans = expans?.length > 0
|
||||
isObject = @variable.isObject()
|
||||
isArray = @variable.isArray()
|
||||
|
||||
vvar = value.compileToFragments o, LEVEL_LIST
|
||||
vvarText = fragmentsToText vvar
|
||||
assigns = []
|
||||
expandedIdx = false
|
||||
|
||||
# At this point, there are several things to destructure. So the `fn()` in
|
||||
# `{a, b} = fn()` must be cached, for example. Make vvar into a simple
|
||||
@@ -2402,79 +2430,108 @@ exports.Assign = class Assign extends Base
|
||||
vvar = [@makeCode ref]
|
||||
vvarText = ref
|
||||
|
||||
# And here comes the big loop that handles all of these cases:
|
||||
# `[a, b] = c`
|
||||
# `[a..., b] = c`
|
||||
# `[..., a, b] = c`
|
||||
# `[@a, b] = c`
|
||||
# `[a = 1, b] = c`
|
||||
# `{a, b} = c`
|
||||
# `{@a, b} = c`
|
||||
# `{a = 1, b} = c`
|
||||
# etc.
|
||||
for obj, i in objects
|
||||
idx = i
|
||||
if not expandedIdx and obj instanceof Splat
|
||||
name = obj.name.unwrap().value
|
||||
obj = obj.unwrap()
|
||||
val = "#{olen} <= #{vvarText}.length ? #{utility 'slice', o}.call(#{vvarText}, #{i}"
|
||||
rest = olen - i - 1
|
||||
if rest isnt 0
|
||||
ivar = o.scope.freeVariable 'i', single: true
|
||||
val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
|
||||
else
|
||||
val += ") : []"
|
||||
val = new Literal val
|
||||
expandedIdx = "#{ivar}++"
|
||||
else if not expandedIdx and obj instanceof Expansion
|
||||
rest = olen - i - 1
|
||||
if rest isnt 0
|
||||
if rest is 1
|
||||
expandedIdx = "#{vvarText}.length - 1"
|
||||
else
|
||||
ivar = o.scope.freeVariable 'i', single: true
|
||||
val = new Literal "#{ivar} = #{vvarText}.length - #{rest}"
|
||||
expandedIdx = "#{ivar}++"
|
||||
assigns.push val.compileToFragments o, LEVEL_LIST
|
||||
continue
|
||||
else
|
||||
if obj instanceof Splat or obj instanceof Expansion
|
||||
obj.error "multiple splats/expansions are disallowed in an assignment"
|
||||
defaultValue = undefined
|
||||
if obj instanceof Assign and obj.context is 'object'
|
||||
# A regular object pattern-match.
|
||||
{variable: {base: idx}, value: obj} = obj
|
||||
if obj instanceof Assign
|
||||
defaultValue = obj.value
|
||||
obj = obj.variable
|
||||
else
|
||||
if obj instanceof Assign
|
||||
defaultValue = obj.value
|
||||
obj = obj.variable
|
||||
idx = if isObject
|
||||
# A shorthand `{a, b, @c} = val` pattern-match.
|
||||
if obj.this
|
||||
obj.properties[0].name
|
||||
else
|
||||
new PropertyName obj.unwrap().value
|
||||
else
|
||||
# A regular array pattern-match.
|
||||
new Literal expandedIdx or idx
|
||||
name = obj.unwrap().value
|
||||
acc = idx.unwrap() instanceof PropertyName
|
||||
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
|
||||
if defaultValue
|
||||
defaultValue.isDefaultValue = yes
|
||||
val = new Op '?', val, defaultValue
|
||||
if name?
|
||||
message = isUnassignable name
|
||||
obj.error message if message
|
||||
unless obj instanceof Elision
|
||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
|
||||
else
|
||||
# Output `Elision` only if `idx` is `i++`, e.g. expandedIdx.
|
||||
assigns.push idx.compileToFragments o, LEVEL_LIST if expandedIdx
|
||||
slicer = (type) -> (vvar, start, end = no) ->
|
||||
args = [new IdentifierLiteral(vvar), new NumberLiteral(start)]
|
||||
args.push new NumberLiteral end if end
|
||||
slice = new Value (new IdentifierLiteral utility type, o), [new Access new PropertyName 'call']
|
||||
new Value new Call slice, args
|
||||
|
||||
# Helper which outputs `[].slice` code.
|
||||
compSlice = slicer "slice"
|
||||
|
||||
# Helper which outputs `[].splice` code.
|
||||
compSplice = slicer "splice"
|
||||
|
||||
# Check if `objects` array contains object spread (`{a, r...}`), e.g. `[a, b, {c, r...}]`.
|
||||
hasObjSpreads = (objs) ->
|
||||
(i for obj, i in objs when obj.base instanceof Obj and obj.base.hasSplat())
|
||||
|
||||
# Check if `objects` array contains any instance of `Assign`, e.g. {a:1}.
|
||||
hasObjAssigns = (objs) ->
|
||||
(i for obj, i in objs when obj instanceof Assign and obj.context is 'object')
|
||||
|
||||
# Check if `objects` array contains any unassignable object.
|
||||
objIsUnassignable = (objs) ->
|
||||
return yes for obj in objs when not obj.isAssignable()
|
||||
no
|
||||
|
||||
# `objects` are complex when there is object spread ({a...}), object assign ({a:1}),
|
||||
# unassignable object, or just a single node.
|
||||
complexObjects = (objs) ->
|
||||
hasObjSpreads(objs).length or hasObjAssigns(objs).length or objIsUnassignable(objs) or olen is 1
|
||||
|
||||
# "Complex" `objects` are processed in a loop.
|
||||
# Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
|
||||
loopObjects = (objs, vvar, vvarTxt) =>
|
||||
objSpreads = hasObjSpreads objs
|
||||
for obj, i in objs
|
||||
# `Elision` can be skipped.
|
||||
continue if obj instanceof Elision
|
||||
# If `obj` is {a: 1}
|
||||
if obj instanceof Assign and obj.context is 'object'
|
||||
{variable: {base: idx}, value: vvar} = obj
|
||||
{variable: vvar} = vvar if vvar instanceof Assign
|
||||
idx =
|
||||
if vvar.this
|
||||
vvar.properties[0].name
|
||||
else
|
||||
new PropertyName vvar.unwrap().value
|
||||
acc = idx.unwrap() instanceof PropertyName
|
||||
vval = new Value value, [new (if acc then Access else Index) idx]
|
||||
else
|
||||
# `obj` is [a...], {a...} or a
|
||||
vvar = switch
|
||||
when obj instanceof Splat then new Value obj.name
|
||||
when i in objSpreads then new Value obj.base
|
||||
else obj
|
||||
vval = switch
|
||||
when obj instanceof Splat then compSlice(vvarTxt, i)
|
||||
else new Value new Literal(vvarTxt), [new Index new NumberLiteral i]
|
||||
message = isUnassignable vvar.unwrap().value
|
||||
vvar.error message if message
|
||||
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, 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, vvar, vvarTxt) ->
|
||||
if complexObjects objs
|
||||
loopObjects objs, vvar, vvarTxt
|
||||
else
|
||||
assignObjects objs, vvar, vvarTxt
|
||||
|
||||
# In case there is `Splat` or `Expansion` in `objects`,
|
||||
# we can split array in two simple subarrays.
|
||||
# `Splat` [a, b, c..., d, e] can be split into [a, b, c...] and [d, e].
|
||||
# `Expansion` [a, b, ..., c, d] can be split into [a, b] and [c, d].
|
||||
# Examples:
|
||||
# a) `Splat`
|
||||
# CS: [a, b, c..., d, e] = arr
|
||||
# JS: [a, b, ...c] = arr, [d, e] = splice.call(c, -2)
|
||||
# b) `Expansion`
|
||||
# CS: [a, b, ..., d, e] = arr
|
||||
# JS: [a, b] = arr, [d, e] = slice.call(arr, -2)
|
||||
if splatsAndExpans.length
|
||||
expIdx = splatsAndExpans[0]
|
||||
leftObjs = objects.slice 0, expIdx + (if isSplat then 1 else 0)
|
||||
rightObjs = objects.slice expIdx + 1
|
||||
processObjects leftObjs, vvar, vvarText if leftObjs.length isnt 0
|
||||
if rightObjs.length isnt 0
|
||||
# Slice or splice `objects`.
|
||||
refExp = switch
|
||||
when isSplat then compSplice objects[expIdx].unwrapAll().value, rightObjs.length * -1
|
||||
when isExpans then compSlice vvarText, rightObjs.length * -1
|
||||
if complexObjects rightObjs
|
||||
restVar = refExp
|
||||
refExp = o.scope.freeVariable 'ref'
|
||||
assigns.push [@makeCode(refExp + ' = '), restVar.compileToFragments(o, LEVEL_LIST)...]
|
||||
processObjects rightObjs, vvar, refExp
|
||||
else
|
||||
# There is no `Splat` or `Expansion` in `objects`.
|
||||
processObjects objects, vvar, vvarText
|
||||
assigns.push vvar unless top or @subpattern
|
||||
fragments = @joinFragmentArrays assigns, ', '
|
||||
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments
|
||||
@@ -2597,14 +2654,24 @@ exports.Code = class Code extends Base
|
||||
|
||||
# Check for duplicate parameters and separate `this` assignments.
|
||||
paramNames = []
|
||||
@eachParamName (name, node, param) ->
|
||||
@eachParamName (name, node, param, obj) ->
|
||||
node.error "multiple parameters named '#{name}'" if name in paramNames
|
||||
paramNames.push name
|
||||
|
||||
if node.this
|
||||
name = node.properties[0].name.value
|
||||
name = "_#{name}" if name in JS_FORBIDDEN
|
||||
target = new IdentifierLiteral o.scope.freeVariable name
|
||||
param.renameParam node, target
|
||||
target = new IdentifierLiteral o.scope.freeVariable name, reserve: no
|
||||
# `Param` is object destructuring with a default value: ({@prop = 1}) ->
|
||||
# In a case when the variable name is already reserved, we have to assign
|
||||
# a new variable name to the destructured variable: ({prop:prop1 = 1}) ->
|
||||
replacement =
|
||||
if param.name instanceof Obj and obj instanceof Assign and
|
||||
obj.operatorToken.value is '='
|
||||
new Assign (new IdentifierLiteral name), target, 'object' #, operatorToken: new Literal ':'
|
||||
else
|
||||
target
|
||||
param.renameParam node, replacement
|
||||
thisAssignments.push new Assign node, target
|
||||
|
||||
# Parse the parameters, adding them to the list of parameters to put in the
|
||||
@@ -2835,7 +2902,9 @@ exports.Code = class Code extends Base
|
||||
# cannot be given an argument with a reference to `this`, as that would
|
||||
# be referencing `this` before calling `super`.
|
||||
unless child.variable.accessor
|
||||
Block.wrap(child.args).traverseChildren yes, (node) =>
|
||||
childArgs = child.args.filter (arg) ->
|
||||
arg not instanceof Class and (arg not instanceof Code or arg.bound)
|
||||
Block.wrap(childArgs).traverseChildren yes, (node) =>
|
||||
node.error "Can't call super with @params in derived class constructors" if node.this
|
||||
seenSuper = yes
|
||||
iterator child
|
||||
@@ -2893,12 +2962,14 @@ exports.Param = class Param extends Base
|
||||
# `name` is the name of the parameter and `node` is the AST node corresponding
|
||||
# to that name.
|
||||
eachName: (iterator, name = @name) ->
|
||||
atParam = (obj) => iterator "@#{obj.properties[0].name.value}", obj, @
|
||||
atParam = (obj, originalObj = null) => iterator "@#{obj.properties[0].name.value}", obj, @, originalObj
|
||||
# * simple literals `foo`
|
||||
return iterator name.value, name, @ if name instanceof Literal
|
||||
# * at-params `@foo`
|
||||
return atParam name if name instanceof Value
|
||||
for obj in name.objects ? []
|
||||
# Save original obj.
|
||||
nObj = obj
|
||||
# * destructured parameter with default value
|
||||
if obj instanceof Assign and not obj.context?
|
||||
obj = obj.variable
|
||||
@@ -2920,7 +2991,7 @@ exports.Param = class Param extends Base
|
||||
@eachName iterator, obj.base
|
||||
# * at-params within destructured parameters `{@foo}`
|
||||
else if obj.this
|
||||
atParam obj
|
||||
atParam obj, nObj
|
||||
# * simple destructured parameters {foo}
|
||||
else iterator obj.base.value, obj.base, @
|
||||
else if obj instanceof Elision
|
||||
@@ -2937,7 +3008,14 @@ exports.Param = class Param extends Base
|
||||
if parent instanceof Obj
|
||||
key = node
|
||||
key = node.properties[0].name if node.this
|
||||
new Assign new Value(key), newNode, 'object'
|
||||
# No need to assign a new variable for the destructured variable if the variable isn't reserved.
|
||||
# Examples:
|
||||
# `({@foo}) ->` should compile to `({foo}) { this.foo = foo}`
|
||||
# `foo = 1; ({@foo}) ->` should compile to `foo = 1; ({foo:foo1}) { this.foo = foo1 }`
|
||||
if node.this and key.value is newNode.value
|
||||
new Value newNode
|
||||
else
|
||||
new Assign new Value(key), newNode, 'object'
|
||||
else
|
||||
newNode
|
||||
|
||||
@@ -3647,7 +3725,7 @@ exports.For = class For extends While
|
||||
body = Block.wrap [new If @guard, body] if @guard
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, if @from then new IdentifierLiteral kvar else new Literal "#{svar}[#{kvar}]"
|
||||
defPartFragments = [].concat @makeCode(defPart), @pluckDirectCall(o, body)
|
||||
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
if @object
|
||||
forPartFragments = [@makeCode("#{kvar} in #{svar}")]
|
||||
@@ -3658,9 +3736,7 @@ exports.For = class For extends While
|
||||
if bodyFragments and bodyFragments.length > 0
|
||||
bodyFragments = [].concat @makeCode('\n'), bodyFragments, @makeCode('\n')
|
||||
|
||||
fragments = []
|
||||
if defPartFragments? and fragmentsToText(defPartFragments) isnt ''
|
||||
fragments = fragments.concat defPartFragments
|
||||
fragments = [@makeCode(defPart)]
|
||||
fragments.push @makeCode(resultPart) if resultPart
|
||||
fragments = fragments.concat @makeCode(@tab), @makeCode( 'for ('),
|
||||
forPartFragments, @makeCode(") {#{guardPart}#{varPart}"), bodyFragments,
|
||||
@@ -3668,26 +3744,6 @@ exports.For = class For extends While
|
||||
fragments.push @makeCode(returnResult) if returnResult
|
||||
fragments
|
||||
|
||||
pluckDirectCall: (o, body) ->
|
||||
defs = []
|
||||
for expr, idx in body.expressions
|
||||
expr = expr.unwrapAll()
|
||||
continue unless expr instanceof Call
|
||||
val = expr.variable?.unwrapAll()
|
||||
continue unless (val instanceof Code) or
|
||||
(val instanceof Value and
|
||||
val.base?.unwrapAll() instanceof Code and
|
||||
val.properties.length is 1 and
|
||||
val.properties[0].name?.value in ['call', 'apply'])
|
||||
fn = val.base?.unwrapAll() or val
|
||||
ref = new IdentifierLiteral o.scope.freeVariable 'fn'
|
||||
base = new Value ref
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs = defs.concat @makeCode(@tab), (new Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), @makeCode(';\n')
|
||||
defs
|
||||
|
||||
#### Switch
|
||||
|
||||
# A JavaScript *switch* statement. Converts into a returnable expression on-demand.
|
||||
|
||||
@@ -263,6 +263,20 @@ exports.Rewriter = class Rewriter
|
||||
stack.pop()
|
||||
start = stack.pop()
|
||||
|
||||
inControlFlow = =>
|
||||
seenFor = @findTagsBackwards(i, ['FOR']) and @findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM'])
|
||||
controlFlow = seenFor or @findTagsBackwards i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']
|
||||
return no unless controlFlow
|
||||
isFunc = no
|
||||
tagCurrentLine = token[2].first_line
|
||||
@detectEnd i,
|
||||
(token, i) -> token[0] in LINEBREAKS
|
||||
(token, i) ->
|
||||
[prevTag, ,{first_line}] = tokens[i - 1] || []
|
||||
isFunc = tagCurrentLine is first_line and prevTag in ['->', '=>']
|
||||
returnOnNegativeLevel: yes
|
||||
isFunc
|
||||
|
||||
# Recognize standard implicit calls like
|
||||
# f a, f() b, f? c, h[0] d etc.
|
||||
# Added support for spread dots on the left side: f ...a
|
||||
@@ -271,7 +285,8 @@ exports.Rewriter = class Rewriter
|
||||
(nextTag in IMPLICIT_CALL or
|
||||
(nextTag is '...' and @tag(i + 2) in IMPLICIT_CALL and not @findTagsBackwards(i, ['INDEX_START', '['])) or
|
||||
nextTag in IMPLICIT_UNSPACED_CALL and
|
||||
not nextToken.spaced and not nextToken.newLine)
|
||||
not nextToken.spaced and not nextToken.newLine) and
|
||||
not inControlFlow()
|
||||
tag = token[0] = 'FUNC_EXIST' if tag is '?'
|
||||
startImplicitCall i + 1
|
||||
return forward(2)
|
||||
@@ -343,11 +358,14 @@ exports.Rewriter = class Rewriter
|
||||
stackItem[2].sameLine = no if isImplicitObject stackItem
|
||||
|
||||
newLine = prevTag is 'OUTDENT' or prevToken.newLine
|
||||
if tag in IMPLICIT_END or tag in CALL_CLOSERS and newLine
|
||||
if tag in IMPLICIT_END or
|
||||
(tag in CALL_CLOSERS and newLine) or
|
||||
(tag in ['..', '...'] and @findTagsBackwards(i, ["INDEX_START"]))
|
||||
while inImplicit()
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()
|
||||
# Close implicit calls when reached end of argument list
|
||||
if inImplicitCall() and prevTag isnt ','
|
||||
if inImplicitCall() and prevTag isnt ',' or
|
||||
(prevTag is ',' and tag is 'TERMINATOR' and not nextTag?)
|
||||
endImplicitCall()
|
||||
# Close implicit objects such as:
|
||||
# return a: 1, b: 2 unless true
|
||||
@@ -544,20 +562,49 @@ exports.Rewriter = class Rewriter
|
||||
# blocks are added.
|
||||
normalizeLines: ->
|
||||
starter = indent = outdent = null
|
||||
leading_switch_when = null
|
||||
leading_if_then = null
|
||||
# Count `THEN` tags
|
||||
ifThens = []
|
||||
|
||||
condition = (token, i) ->
|
||||
token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
|
||||
not (token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE) and
|
||||
not (token[0] is 'ELSE' and starter isnt 'THEN') and
|
||||
not (token[0] is 'ELSE' and
|
||||
(starter isnt 'THEN' or (leading_if_then or leading_switch_when))) and
|
||||
not (token[0] in ['CATCH', 'FINALLY'] and starter in ['->', '=>']) or
|
||||
token[0] in CALL_CLOSERS and
|
||||
(@tokens[i - 1].newLine or @tokens[i - 1][0] is 'OUTDENT')
|
||||
|
||||
action = (token, i) ->
|
||||
ifThens.pop() if token[0] is 'ELSE' and starter is 'THEN'
|
||||
@tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent
|
||||
|
||||
closeElseTag = (tokens, i) =>
|
||||
tlen = ifThens.length
|
||||
return i unless tlen > 0
|
||||
lastThen = ifThens.pop()
|
||||
[, outdentElse] = @indentation tokens[lastThen]
|
||||
# Insert `OUTDENT` to close inner `IF`.
|
||||
outdentElse[1] = tlen*2
|
||||
tokens.splice(i, 0, outdentElse)
|
||||
# Insert `OUTDENT` to close outer `IF`.
|
||||
outdentElse[1] = 2
|
||||
tokens.splice(i + 1, 0, outdentElse)
|
||||
# Remove outdents from the end.
|
||||
@detectEnd i + 2,
|
||||
(token, i) -> token[0] in ['OUTDENT', 'TERMINATOR']
|
||||
(token, i) ->
|
||||
if @tag(i) is 'OUTDENT' and @tag(i + 1) is 'OUTDENT'
|
||||
tokens.splice i, 2
|
||||
i + 2
|
||||
|
||||
@scanTokens (token, i, tokens) ->
|
||||
[tag] = token
|
||||
conditionTag = tag in ['->', '=>'] and
|
||||
@findTagsBackwards(i, ['IF', 'WHILE', 'FOR', 'UNTIL', 'SWITCH', 'WHEN', 'LEADING_WHEN', '[', 'INDEX_START']) and
|
||||
not (@findTagsBackwards i, ['THEN', '..', '...'])
|
||||
|
||||
if tag is 'TERMINATOR'
|
||||
if @tag(i + 1) is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
|
||||
tokens.splice i, 1, @indentation()...
|
||||
@@ -574,10 +621,18 @@ exports.Rewriter = class Rewriter
|
||||
tokens.splice i + 1, 0, indent, outdent
|
||||
return 1
|
||||
if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and
|
||||
not (tag is 'ELSE' and @tag(i + 1) is 'IF')
|
||||
not (tag is 'ELSE' and @tag(i + 1) is 'IF') and
|
||||
not conditionTag
|
||||
starter = tag
|
||||
[indent, outdent] = @indentation tokens[i]
|
||||
indent.fromThen = true if starter is 'THEN'
|
||||
if tag is 'THEN'
|
||||
leading_switch_when = @findTagsBackwards(i, ['LEADING_WHEN']) and @tag(i + 1) is 'IF'
|
||||
leading_if_then = @findTagsBackwards(i, ['IF']) and @tag(i + 1) is 'IF'
|
||||
ifThens.push i if tag is 'THEN' and @findTagsBackwards(i, ['IF'])
|
||||
# `ELSE` tag is not closed.
|
||||
if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
|
||||
i = closeElseTag tokens, i
|
||||
tokens.splice i + 1, 0, indent
|
||||
@detectEnd i + 2, condition, action
|
||||
tokens.splice i, 1 if tag is 'THEN'
|
||||
|
||||
@@ -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']]
|
||||
|
||||
@@ -1874,3 +1874,28 @@ test "#4827: executable class body wrappers have correct context", ->
|
||||
o = {}
|
||||
test.call o
|
||||
ok typeof o.A is typeof o.B is 'function'
|
||||
|
||||
test "#4868: Incorrect ‘Can’t call super with @params’ error", ->
|
||||
class A
|
||||
constructor: (@func = ->) ->
|
||||
@x = 1
|
||||
@func()
|
||||
|
||||
class B extends A
|
||||
constructor: ->
|
||||
super -> @x = 2
|
||||
|
||||
a = new A
|
||||
b = new B
|
||||
eq 1, a.x
|
||||
eq 2, b.x
|
||||
|
||||
class C
|
||||
constructor: (@c = class) -> @c
|
||||
|
||||
class D extends C
|
||||
constructor: ->
|
||||
super class then constructor: (@a) -> @a = 3
|
||||
|
||||
d = new (new D).c
|
||||
eq 3, d.a
|
||||
@@ -170,3 +170,10 @@ test "using transpile from the Node API requires an object", ->
|
||||
test "transpile option applies to imported .coffee files", ->
|
||||
return if global.testingBrowser
|
||||
doesNotThrow -> transpile 'run', "import { getSep } from './test/importing/transpile_import'\ngetSep()"
|
||||
|
||||
test "#3306: trailing comma in a function call in the last line", ->
|
||||
eqJS '''
|
||||
foo bar,
|
||||
''', '''
|
||||
foo(bar);
|
||||
'''
|
||||
@@ -484,3 +484,806 @@ test "#4267: lots of for-loops in the same scope", ->
|
||||
true
|
||||
"""
|
||||
ok CoffeeScript.eval(code)
|
||||
|
||||
# Test for issue #2342: Lexer: Inline `else` binds to wrong `if`/`switch`
|
||||
test "#2343: if / then / if / then / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
if a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
t = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
u = ->
|
||||
if a then if b
|
||||
if c then d else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
|
||||
v = ->
|
||||
if a then if b
|
||||
if c then d else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
|
||||
w = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else
|
||||
if g then h
|
||||
else i
|
||||
|
||||
x = -> if a then if b then if c then d else if e then f else if g then h else i
|
||||
|
||||
y = -> if a then if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
test "#2343: if / then / if / then / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
j = 5
|
||||
k = 6
|
||||
|
||||
s = ->
|
||||
if a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
e
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
k
|
||||
|
||||
t = ->
|
||||
if a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
k
|
||||
|
||||
u = ->
|
||||
if a
|
||||
if b
|
||||
if c then d else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else j
|
||||
else k
|
||||
|
||||
v = ->
|
||||
if a
|
||||
if b
|
||||
if c then d else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else j else k
|
||||
|
||||
w = ->
|
||||
if a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else
|
||||
if g then h
|
||||
else i
|
||||
else j else k
|
||||
|
||||
x = -> if a then if b then if c then d else if e then f else if g then h else i else j else k
|
||||
|
||||
y = -> if a then (if b then (if c then d else (if e then f else (if g then h else i))) else j) else k
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq 5, s()
|
||||
eq 5, t()
|
||||
eq 5, u()
|
||||
eq 5, v()
|
||||
eq 5, w()
|
||||
eq 5, x()
|
||||
eq 5, y()
|
||||
|
||||
a = no
|
||||
eq 6, s()
|
||||
eq 6, t()
|
||||
eq 6, u()
|
||||
eq 6, v()
|
||||
eq 6, w()
|
||||
eq 6, x()
|
||||
eq 6, y()
|
||||
|
||||
|
||||
test "#2343: switch / when / then / if / then / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else
|
||||
if e
|
||||
f
|
||||
else
|
||||
if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a then if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a then if b then if c then d
|
||||
else if e then f
|
||||
else if g then h else i
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f
|
||||
else if g then h else i
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a then if b then if c then d else if e then f else if g then h else i
|
||||
|
||||
y = -> switch
|
||||
when a then if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
test "#2343: switch / when / then / if / then / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
0
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else 0
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d
|
||||
else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else 0
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d else if e then f else if g then h else i
|
||||
else 0
|
||||
|
||||
y = -> switch
|
||||
when a
|
||||
if b then (if c then d else (if e then f else (if g then h else i)))
|
||||
else 0
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq undefined, s()
|
||||
eq undefined, t()
|
||||
eq undefined, u()
|
||||
eq undefined, v()
|
||||
eq undefined, w()
|
||||
eq undefined, x()
|
||||
eq undefined, y()
|
||||
|
||||
b = yes
|
||||
a = no
|
||||
eq 0, s()
|
||||
eq 0, t()
|
||||
eq 0, u()
|
||||
eq 0, v()
|
||||
eq 0, w()
|
||||
eq 0, x()
|
||||
eq 0, y()
|
||||
|
||||
test "#2343: switch / when / then / if / then / else / else / else", ->
|
||||
a = b = yes
|
||||
c = e = g = no
|
||||
d = 1
|
||||
f = 2
|
||||
h = 3
|
||||
i = 4
|
||||
j = 5
|
||||
|
||||
s = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else
|
||||
i
|
||||
else
|
||||
j
|
||||
else
|
||||
0
|
||||
|
||||
t = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else
|
||||
j
|
||||
else 0
|
||||
|
||||
u = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c
|
||||
d
|
||||
else if e
|
||||
f
|
||||
else if g
|
||||
h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
v = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e
|
||||
f
|
||||
else if g then h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
w = ->
|
||||
switch
|
||||
when a
|
||||
if b
|
||||
if c then d
|
||||
else if e then f
|
||||
else if g then h
|
||||
else i
|
||||
else j
|
||||
else 0
|
||||
|
||||
x = ->
|
||||
switch
|
||||
when a
|
||||
if b then if c then d else if e then f else if g then h else i else j
|
||||
else 0
|
||||
|
||||
y = -> switch
|
||||
when a
|
||||
if b then (if c then d else (if e then f else (if g then h else i))) else j
|
||||
else 0
|
||||
|
||||
eq 4, s()
|
||||
eq 4, t()
|
||||
eq 4, u()
|
||||
eq 4, v()
|
||||
eq 4, w()
|
||||
eq 4, x()
|
||||
eq 4, y()
|
||||
|
||||
c = yes
|
||||
eq 1, s()
|
||||
eq 1, t()
|
||||
eq 1, u()
|
||||
eq 1, v()
|
||||
eq 1, w()
|
||||
eq 1, x()
|
||||
eq 1, y()
|
||||
|
||||
b = no
|
||||
eq 5, s()
|
||||
eq 5, t()
|
||||
eq 5, u()
|
||||
eq 5, v()
|
||||
eq 5, w()
|
||||
eq 5, x()
|
||||
eq 5, y()
|
||||
|
||||
b = yes
|
||||
a = no
|
||||
eq 0, s()
|
||||
eq 0, t()
|
||||
eq 0, u()
|
||||
eq 0, v()
|
||||
eq 0, w()
|
||||
eq 0, x()
|
||||
eq 0, y()
|
||||
|
||||
# Test for issue #3921: Inline function without parentheses used in condition fails to compile
|
||||
test "#3921: `if` & `unless`", ->
|
||||
a = {}
|
||||
eq a, if do -> no then undefined else a
|
||||
a1 = undefined
|
||||
if do -> yes
|
||||
a1 = a
|
||||
eq a, a1
|
||||
|
||||
b = {}
|
||||
eq b, unless do -> no then b else undefined
|
||||
b1 = undefined
|
||||
unless do -> no
|
||||
b1 = b
|
||||
eq b, b1
|
||||
|
||||
c = 0
|
||||
if (arg = undefined) -> yes then c++
|
||||
eq 1, c
|
||||
d = 0
|
||||
if (arg = undefined) -> yes
|
||||
d++
|
||||
eq 1, d
|
||||
|
||||
answer = 'correct'
|
||||
eq answer, if do -> 'wrong' then 'correct' else 'wrong'
|
||||
eq answer, unless do -> no then 'correct' else 'wrong'
|
||||
statm1 = undefined
|
||||
if do -> 'wrong'
|
||||
statm1 = 'correct'
|
||||
eq answer, statm1
|
||||
statm2 = undefined
|
||||
unless do -> no
|
||||
statm2 = 'correct'
|
||||
eq answer, statm2
|
||||
|
||||
test "#3921: `post if`", ->
|
||||
a = {}
|
||||
eq a, a unless do -> no
|
||||
a1 = a if do -> yes
|
||||
eq a, a1
|
||||
|
||||
c = 0
|
||||
c++ if (arg = undefined) -> yes
|
||||
eq 1, c
|
||||
d = 0
|
||||
d++ if (arg = undefined) -> yes
|
||||
eq 1, d
|
||||
|
||||
answer = 'correct'
|
||||
eq answer, 'correct' if do -> 'wrong'
|
||||
eq answer, 'correct' unless do -> not 'wrong'
|
||||
statm1 = undefined
|
||||
statm1 = 'correct' if do -> 'wrong'
|
||||
eq answer, statm1
|
||||
statm2 = undefined
|
||||
statm2 = 'correct' unless do -> not 'wrong'
|
||||
eq answer, statm2
|
||||
|
||||
test "Issue 3921: `while` & `until`", ->
|
||||
i = 5
|
||||
assert = (a) -> ok 5 > a > 0
|
||||
result1 = while do (num = 1) -> i -= num
|
||||
assert i
|
||||
i
|
||||
ok result1.join(' ') is '4 3 2 1'
|
||||
|
||||
j = 5
|
||||
result2 = until do (num = 1) -> (j -= num) < 1
|
||||
assert j
|
||||
j
|
||||
ok result2.join(' ') is '4 3 2 1'
|
||||
|
||||
test "#3921: `switch`", ->
|
||||
i = 1
|
||||
a = switch do (m = 2) -> i * m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "two", a
|
||||
|
||||
j = 12
|
||||
b = switch do (m = 3) -> j / m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "four", b
|
||||
|
||||
k = 20
|
||||
c = switch do (m = 4) -> k / m
|
||||
when 5 then "five"
|
||||
when 4 then "four"
|
||||
when 3 then "three"
|
||||
when 2 then "two"
|
||||
when 1 then "one"
|
||||
else "none"
|
||||
eq "five", c
|
||||
|
||||
# Issue #3441: Parentheses wrapping expression throw invalid error in `then` clause
|
||||
test "#3441: `StatementLiteral` in parentheses", ->
|
||||
i = 0
|
||||
r1 = ((i++; break) while i < 10)
|
||||
arrayEq r1, []
|
||||
|
||||
i = 0
|
||||
r2 = ((i++; continue) while i < 10)
|
||||
arrayEq r2, []
|
||||
|
||||
i = 0
|
||||
r4 = while i < 10 then (i++; break)
|
||||
arrayEq r4, []
|
||||
|
||||
i = 0
|
||||
r5 = while i < 10 then (i++; continue)
|
||||
arrayEq r5, []
|
||||
|
||||
arr = [0..9]
|
||||
r6 = ((a; break) for a in arr)
|
||||
arrayEq r6, []
|
||||
|
||||
r7 = ((a; continue) for a in arr)
|
||||
arrayEq r7, []
|
||||
|
||||
r8 = for a in arr then (a; break)
|
||||
arrayEq r8, []
|
||||
|
||||
r9 = for a in arr then (a; continue)
|
||||
arrayEq r9, []
|
||||
|
||||
# Issue #3909: backslash to break line in `for` loops throw syntax error
|
||||
test "#3909: backslash `for own ... of`", ->
|
||||
|
||||
obj = {a: 1, b: 2, c: 3}
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for own key of obj )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for own key of obj )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for own key of obj )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for own key of obj )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for own key of \
|
||||
obj )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for own key of obj \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
own key of obj )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for own \
|
||||
key of obj )
|
||||
arrayEq x8, arr
|
||||
|
||||
x9 = ( key for own key \
|
||||
of obj )
|
||||
arrayEq x9, arr
|
||||
|
||||
|
||||
test "#3909: backslash `for ... of`", ->
|
||||
obj = {a: 1, b: 2, c: 3}
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for key of obj )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for key of obj )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for key of obj )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for key of obj )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for key of \
|
||||
obj )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for key of obj \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
key of obj )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for key \
|
||||
of obj )
|
||||
arrayEq x8, arr
|
||||
|
||||
|
||||
test "#3909: backslash `for ... in`", ->
|
||||
arr = ['a', 'b', 'c']
|
||||
|
||||
x1 \
|
||||
= ( key for key in arr )
|
||||
arrayEq x1, arr
|
||||
|
||||
x2 = \
|
||||
( key for key in arr )
|
||||
arrayEq x2, arr
|
||||
|
||||
x3 = ( \
|
||||
key for key in arr )
|
||||
arrayEq x3, arr
|
||||
|
||||
x4 = ( key \
|
||||
for key in arr )
|
||||
arrayEq x4, arr
|
||||
|
||||
x5 = ( key for key in \
|
||||
arr )
|
||||
arrayEq x5, arr
|
||||
|
||||
x6 = ( key for key in arr \
|
||||
)
|
||||
arrayEq x6, arr
|
||||
|
||||
x7 = ( key for \
|
||||
key in arr )
|
||||
arrayEq x7, arr
|
||||
|
||||
x8 = ( key for key \
|
||||
in arr )
|
||||
arrayEq x8, arr
|
||||
|
||||
test "#4871: `else if` no longer output together ", ->
|
||||
eqJS '''
|
||||
if a then b else if c then d else if e then f else g
|
||||
''',
|
||||
'''
|
||||
if (a) {
|
||||
b;
|
||||
} else if (c) {
|
||||
d;
|
||||
} else if (e) {
|
||||
f;
|
||||
} else {
|
||||
g;
|
||||
}
|
||||
'''
|
||||
|
||||
eqJS '''
|
||||
if no
|
||||
1
|
||||
else if yes
|
||||
2
|
||||
''',
|
||||
'''
|
||||
if (false) {
|
||||
1;
|
||||
} else if (true) {
|
||||
2;
|
||||
}
|
||||
'''
|
||||
|
||||
@@ -1777,3 +1777,53 @@ test "#4811: '///' inside a heregex comment does not close the heregex", ->
|
||||
/// .* # comment ///
|
||||
^^^
|
||||
'''
|
||||
|
||||
test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
|
||||
assertErrorFormat '''
|
||||
for a in b do ->
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected do
|
||||
for a in b do ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
for a in b ->
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected ->
|
||||
for a in b ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
for a in b do =>
|
||||
''','''
|
||||
[stdin]:1:12: error: unexpected do
|
||||
for a in b do =>
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
while a do ->
|
||||
''','''
|
||||
[stdin]:1:9: error: unexpected do
|
||||
while a do ->
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
until a do =>
|
||||
''','''
|
||||
[stdin]:1:9: error: unexpected do
|
||||
until a do =>
|
||||
^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
switch
|
||||
when a ->
|
||||
''','''
|
||||
[stdin]:2:10: error: unexpected ->
|
||||
when a ->
|
||||
^^
|
||||
'''
|
||||
@@ -329,6 +329,15 @@ test "Simple Destructuring function arguments with same-named variables in scope
|
||||
eq f([2]), 2
|
||||
eq x, 1
|
||||
|
||||
test "#4843: Bad output when assigning to @prop in destructuring assignment with defaults", ->
|
||||
works = "maybe"
|
||||
drinks = "beer"
|
||||
class A
|
||||
constructor: ({@works = 'no', @drinks = 'wine'}) ->
|
||||
a = new A {works: 'yes', drinks: 'coffee'}
|
||||
eq a.works, 'yes'
|
||||
eq a.drinks, 'coffee'
|
||||
|
||||
test "caching base value", ->
|
||||
|
||||
obj =
|
||||
@@ -795,7 +804,7 @@ test "get and set can be used as class method names", ->
|
||||
eq 4, B.get()
|
||||
eq 5, B.set()
|
||||
|
||||
test "functions named get or set can be used without parentheses when attached to an object; #4524", ->
|
||||
test "#4524: functions named get or set can be used without parentheses when attached to an object", ->
|
||||
obj =
|
||||
get: (x) -> x + 2
|
||||
set: (x) -> x + 3
|
||||
@@ -814,6 +823,8 @@ test "functions named get or set can be used without parentheses when attached t
|
||||
|
||||
eq 12, obj.get 10
|
||||
eq 13, obj.set 10
|
||||
eq 12, obj?.get 10
|
||||
eq 13, obj?.set 10
|
||||
|
||||
eq 14, a.get 10
|
||||
eq 15, a.set 10
|
||||
@@ -836,3 +847,59 @@ test "functions named get or set can be used without parentheses when attached t
|
||||
|
||||
eq 16, b.get value: @ten
|
||||
eq 17, b.set value: @ten
|
||||
|
||||
test "#4836: functions named get or set can be used without parentheses when attached to this or @", ->
|
||||
@get = (x) -> x + 2
|
||||
@set = (x) -> x + 3
|
||||
@a = 4
|
||||
|
||||
eq 12, this.get 10
|
||||
eq 13, this.set 10
|
||||
eq 12, this?.get 10
|
||||
eq 13, this?.set 10
|
||||
eq 6, this.get @a
|
||||
eq 7, this.set @a
|
||||
eq 6, this?.get @a
|
||||
eq 7, this?.set @a
|
||||
|
||||
eq 12, @get 10
|
||||
eq 13, @set 10
|
||||
eq 12, @?.get 10
|
||||
eq 13, @?.set 10
|
||||
eq 6, @get @a
|
||||
eq 7, @set @a
|
||||
eq 6, @?.get @a
|
||||
eq 7, @?.set @a
|
||||
|
||||
test "#4852: functions named get or set can be used without parentheses when attached to this or @, with an argument of an implicit object", ->
|
||||
@get = ({ x }) -> x + 2
|
||||
@set = ({ x }) -> x + 3
|
||||
|
||||
eq 12, @get x: 10
|
||||
eq 13, @set x: 10
|
||||
eq 12, @?.get x: 10
|
||||
eq 13, @?.set x: 10
|
||||
eq 12, this?.get x: 10
|
||||
eq 13, this?.set x: 10
|
||||
|
||||
test "#4473: variable scope in chained calls", ->
|
||||
obj =
|
||||
foo: -> this
|
||||
bar: (a) ->
|
||||
a()
|
||||
this
|
||||
|
||||
obj.foo(a = 1).bar(-> a = 2)
|
||||
eq a, 2
|
||||
|
||||
obj.bar(-> b = 2).foo(b = 1)
|
||||
eq b, 1
|
||||
|
||||
obj.foo(c = 1).bar(-> c = 2).foo(c = 3)
|
||||
eq c, 3
|
||||
|
||||
obj.foo([d, e] = [1, 2]).bar(-> d = 4)
|
||||
eq d, 4
|
||||
|
||||
obj.foo({f} = {f: 1}).bar(-> f = 5)
|
||||
eq f, 5
|
||||
|
||||
@@ -116,3 +116,89 @@ test "#1012 slices with arguments object", ->
|
||||
|
||||
test "#1409: creating large ranges outside of a function body", ->
|
||||
CoffeeScript.eval '[0..100]'
|
||||
|
||||
test "#2047: Infinite loop possible when `for` loop with `range` uses variables", ->
|
||||
up = 1
|
||||
down = -1
|
||||
a = 1
|
||||
b = 5
|
||||
|
||||
testRange = (arg) ->
|
||||
[from, to, step, expectedResult] = arg
|
||||
r = (x for x in [from..to] by step)
|
||||
arrayEq r, expectedResult
|
||||
|
||||
testData = [
|
||||
[1, 5, 1, [1..5]]
|
||||
[1, 5, -1, [1]]
|
||||
[1, 5, up, [1..5]]
|
||||
[1, 5, down, [1]]
|
||||
|
||||
[a, 5, 1, [1..5]]
|
||||
[a, 5, -1, [1]]
|
||||
[a, 5, up, [1..5]]
|
||||
[a, 5, down, [1]]
|
||||
|
||||
[1, b, 1, [1..5]]
|
||||
[1, b, -1, [1]]
|
||||
[1, b, up, [1..5]]
|
||||
[1, b, down, [1]]
|
||||
|
||||
[a, b, 1, [1..5]]
|
||||
[a, b, -1, [1]]
|
||||
[a, b, up, [1..5]]
|
||||
[a, b, down, [1]]
|
||||
|
||||
[5, 1, 1, [5]]
|
||||
[5, 1, -1, [5..1]]
|
||||
[5, 1, up, [5]]
|
||||
[5, 1, down, [5..1]]
|
||||
|
||||
[5, a, 1, [5]]
|
||||
[5, a, -1, [5..1]]
|
||||
[5, a, up, [5]]
|
||||
[5, a, down, [5..1]]
|
||||
|
||||
[b, 1, 1, [5]]
|
||||
[b, 1, -1, [5..1]]
|
||||
[b, 1, up, [5]]
|
||||
[b, 1, down, [5..1]]
|
||||
|
||||
[b, a, 1, [5]]
|
||||
[b, a, -1, [5..1]]
|
||||
[b, a, up, [5]]
|
||||
[b, a, down, [5..1]]
|
||||
]
|
||||
|
||||
testRange d for d in testData
|
||||
|
||||
test "#2047: from, to and step as variables", ->
|
||||
up = 1
|
||||
down = -1
|
||||
a = 1
|
||||
b = 5
|
||||
|
||||
r = (x for x in [a..b] by up)
|
||||
arrayEq r, [1..5]
|
||||
|
||||
r = (x for x in [a..b] by down)
|
||||
arrayEq r, [1]
|
||||
|
||||
r = (x for x in [b..a] by up)
|
||||
arrayEq r, [5]
|
||||
|
||||
r = (x for x in [b..a] by down)
|
||||
arrayEq r, [5..1]
|
||||
|
||||
a = 1
|
||||
b = -1
|
||||
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
|
||||
|
||||
@@ -165,3 +165,9 @@ test "#2953: methods on endpoints in assignment from array splice literal", ->
|
||||
delete Number.prototype.same
|
||||
|
||||
arrayEq [0, 5, 9], list
|
||||
|
||||
test "#1726: `Op` expression in property access causes unexpected results", ->
|
||||
a = [0..2]
|
||||
arrayEq a, a[(!1 in a)..]
|
||||
arrayEq a, a[!1 in a..]
|
||||
arrayEq a[(!1 in a)..], a[(!1 in a)..]
|
||||
|
||||
Reference in New Issue
Block a user