1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00
jashkenas--coffeescript/docs/v2/annotated-source/nodes.html
Geoffrey Booth e5aa758dda
2.2.4 (#5025)
* Update changelog for 2.2.4

* Bump version to 2.2.4; update output
2018-03-29 20:00:45 -07:00

8106 lines
434 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<title>nodes.coffee</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To &hellip;</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page_wrapper">
<div id="jump_page">
<a class="source" href="browser.html">
browser.coffee
</a>
<a class="source" href="cake.html">
cake.coffee
</a>
<a class="source" href="coffeescript.html">
coffeescript.coffee
</a>
<a class="source" href="command.html">
command.coffee
</a>
<a class="source" href="grammar.html">
grammar.coffee
</a>
<a class="source" href="helpers.html">
helpers.coffee
</a>
<a class="source" href="index.html">
index.coffee
</a>
<a class="source" href="lexer.html">
lexer.coffee
</a>
<a class="source" href="nodes.html">
nodes.coffee
</a>
<a class="source" href="optparse.html">
optparse.coffee
</a>
<a class="source" href="register.html">
register.coffee
</a>
<a class="source" href="repl.html">
repl.coffee
</a>
<a class="source" href="rewriter.html">
rewriter.coffee
</a>
<a class="source" href="scope.html">
scope.litcoffee
</a>
<a class="source" href="sourcemap.html">
sourcemap.litcoffee
</a>
</div>
</div>
</li>
</ul>
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>nodes.coffee</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-1">&#182;</a>
</div>
<p><code>nodes.coffee</code> contains all of the node classes for the syntax tree. Most
nodes are created as the result of actions in the <a href="grammar.html">grammar</a>,
but some are created by other nodes as a method of code generation. To convert
the syntax tree into a string of JavaScript code, call <code>compile()</code> on the root.</p>
</div>
<div class="content"><div class='highlight'><pre>
Error.stackTraceLimit = Infinity
{Scope} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./scope'</span>
{isUnassignable, JS_FORBIDDEN} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./lexer'</span></pre></div></div>
</li>
<li id="section-2">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">&#182;</a>
</div>
<p>Import the helpers we plan to use.</p>
</div>
<div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, some,
addDataToNode, attachCommentsToNode, locationDataToString,
throwSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span></pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">&#182;</a>
</div>
<p>Functions required by parser.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.extend = extend
exports.addDataToNode = addDataToNode</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-4">&#182;</a>
</div>
<p>Constant functions for nodes that dont need customization.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">YES</span> = -&gt;</span> <span class="hljs-literal">yes</span>
<span class="hljs-function"><span class="hljs-title">NO</span> = -&gt;</span> <span class="hljs-literal">no</span>
<span class="hljs-function"><span class="hljs-title">THIS</span> = -&gt;</span> <span class="hljs-keyword">this</span>
<span class="hljs-function"><span class="hljs-title">NEGATE</span> = -&gt;</span> @negated = <span class="hljs-keyword">not</span> @negated; <span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">&#182;</a>
</div>
<h3 id="codefragment">CodeFragment</h3>
</div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">&#182;</a>
</div>
<p>The various nodes defined below all compile to a collection of <strong>CodeFragment</strong> objects.
A CodeFragments is a block of generated code, and the location in the source file where the code
came from. CodeFragments can be assembled together into working code just by catting together
all the CodeFragments <code>code</code> snippets, in order.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.CodeFragment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CodeFragment</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(parent, code)</span> -&gt;</span>
@code = <span class="hljs-string">"<span class="hljs-subst">#{code}</span>"</span>
@type = parent?.constructor?.name <span class="hljs-keyword">or</span> <span class="hljs-string">'unknown'</span>
@locationData = parent?.locationData
@comments = parent?.comments
toString: <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#182;</a>
</div>
<p>This is only intended for debugging.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-string">"<span class="hljs-subst">#{@code}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> @locationData <span class="hljs-keyword">then</span> <span class="hljs-string">": "</span> + locationDataToString(@locationData) <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span></pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<p>Convert an array of CodeFragments into a string.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">fragmentsToText</span> = <span class="hljs-params">(fragments)</span> -&gt;</span>
(fragment.code <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments).join(<span class="hljs-string">''</span>)</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<h3 id="base">Base</h3>
</div>
</li>
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>The <strong>Base</strong> is the abstract base class for all nodes in the syntax tree.
Each subclass implements the <code>compileNode</code> method, which performs the
code generation for that node. To compile a node to JavaScript,
call <code>compile</code> on it, which wraps <code>compileNode</code> in some generic extra smarts,
to know when the generated code needs to be wrapped up in a closure.
An options hash is passed and cloned throughout, containing information about
the environment from higher in the tree (such as if a returned value is
being requested by the surrounding function), information about the current
scope, and indentation level.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Base = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Base</span></span>
compile: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
fragmentsToText @compileToFragments o, lvl</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
</div>
<p>Occasionally a node is compiled multiple times, for example to get the name
of a variable to add to scope tracking. When we know that a “premature”
compilation wont result in comments being output, set those comments aside
so that theyre preserved for a later <code>compile</code> call that will result in
the comments being included in the output.</p>
</div>
<div class="content"><div class='highlight'><pre> compileWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl, method = <span class="hljs-string">'compile'</span>)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @comments
@ignoreTheseCommentsTemporarily = @comments
<span class="hljs-keyword">delete</span> @comments
unwrapped = @unwrapAll()
<span class="hljs-keyword">if</span> unwrapped.comments
unwrapped.ignoreTheseCommentsTemporarily = unwrapped.comments
<span class="hljs-keyword">delete</span> unwrapped.comments
fragments = @[method] o, lvl
<span class="hljs-keyword">if</span> @ignoreTheseCommentsTemporarily
@comments = @ignoreTheseCommentsTemporarily
<span class="hljs-keyword">delete</span> @ignoreTheseCommentsTemporarily
<span class="hljs-keyword">if</span> unwrapped.ignoreTheseCommentsTemporarily
unwrapped.comments = unwrapped.ignoreTheseCommentsTemporarily
<span class="hljs-keyword">delete</span> unwrapped.ignoreTheseCommentsTemporarily
fragments
compileNodeWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
@compileWithoutComments o, lvl, <span class="hljs-string">'compileNode'</span></pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>Common logic for determining whether to wrap this node in a closure before
compiling it, or to compile directly. We need to wrap if this node is a
<em>statement</em>, and its not a <em>pureStatement</em>, and were not at
the top level of a block (which would be unnecessary), and we havent
already been asked to return the result (because statements know how to
return results).</p>
</div>
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
o = extend {}, o
o.level = lvl <span class="hljs-keyword">if</span> lvl
node = @unfoldSoak(o) <span class="hljs-keyword">or</span> <span class="hljs-keyword">this</span>
node.tab = o.indent
fragments = <span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.isStatement(o)
node.compileNode o
<span class="hljs-keyword">else</span>
node.compileClosure o
@compileCommentFragments o, node, fragments
fragments
compileToFragmentsWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
@compileWithoutComments o, lvl, <span class="hljs-string">'compileToFragments'</span></pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>Statements converted into expressions via closure-wrapping share a scope
object with their parent closure, to preserve the expected lexical scope.</p>
</div>
<div class="content"><div class='highlight'><pre> compileClosure: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> jumpNode = @jumps()
jumpNode.error <span class="hljs-string">'cannot use a pure statement in an expression'</span>
o.sharedScope = <span class="hljs-literal">yes</span>
func = <span class="hljs-keyword">new</span> Code [], Block.wrap [<span class="hljs-keyword">this</span>]
args = []
<span class="hljs-keyword">if</span> @contains (<span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span> node <span class="hljs-keyword">instanceof</span> SuperCall)
func.bound = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (argumentsNode = @contains isLiteralArguments) <span class="hljs-keyword">or</span> @contains isLiteralThis
args = [<span class="hljs-keyword">new</span> ThisLiteral]
<span class="hljs-keyword">if</span> argumentsNode
meth = <span class="hljs-string">'apply'</span>
args.push <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span>
<span class="hljs-keyword">else</span>
meth = <span class="hljs-string">'call'</span>
func = <span class="hljs-keyword">new</span> Value func, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName meth]
parts = (<span class="hljs-keyword">new</span> Call func, args).compileNode o
<span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> func.isGenerator <span class="hljs-keyword">or</span> func.base?.isGenerator
parts.unshift @makeCode <span class="hljs-string">"(yield* "</span>
parts.push @makeCode <span class="hljs-string">")"</span>
<span class="hljs-keyword">when</span> func.isAsync <span class="hljs-keyword">or</span> func.base?.isAsync
parts.unshift @makeCode <span class="hljs-string">"(await "</span>
parts.push @makeCode <span class="hljs-string">")"</span>
parts
compileCommentFragments: <span class="hljs-function"><span class="hljs-params">(o, node, fragments)</span> -&gt;</span>
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">unless</span> node.comments</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>This is where comments, that are attached to nodes as a <code>comments</code>
property, become <code>CodeFragment</code>s. “Inline block comments,” e.g.
<code>/* */</code>-delimited comments that are interspersed within code on a line,
are added to the current <code>fragments</code> stream. All other fragments are
attached as properties to the nearest preceding or following fragment,
to remain stowaways until they get properly output in <code>compileComments</code>
later on.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">unshiftCommentFragment</span> = <span class="hljs-params">(commentFragment)</span> -&gt;</span>
<span class="hljs-keyword">if</span> commentFragment.unshift</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>Find the first non-comment fragment and insert <code>commentFragment</code>
before it.</p>
</div>
<div class="content"><div class='highlight'><pre> unshiftAfterComments fragments, commentFragment
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
precedingFragment = fragments[fragments.length - <span class="hljs-number">1</span>]
<span class="hljs-keyword">if</span> commentFragment.newLine <span class="hljs-keyword">and</span> precedingFragment.code <span class="hljs-keyword">isnt</span> <span class="hljs-string">''</span> <span class="hljs-keyword">and</span>
<span class="hljs-keyword">not</span> <span class="hljs-regexp">/\n\s*$/</span>.test precedingFragment.code
commentFragment.code = <span class="hljs-string">"\n<span class="hljs-subst">#{commentFragment.code}</span>"</span>
fragments.push commentFragment
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments <span class="hljs-keyword">when</span> comment <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> @compiledComments
@compiledComments.push comment <span class="hljs-comment"># Dont output this comment twice.</span></pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>For block/here comments, denoted by <code>###</code>, that are inline comments
like <code>1 + ### comment ### 2</code>, create fragments and insert them into
the fragments array.
Otherwise attach comment fragments to their closest fragment for now,
so they can be inserted into the output later after all the newlines
have been added.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> comment.here <span class="hljs-comment"># Block comment, delimited by `###`.</span>
commentFragment = <span class="hljs-keyword">new</span> HereComment(comment).compileNode o
<span class="hljs-keyword">else</span> <span class="hljs-comment"># Line comment, delimited by `#`.</span>
commentFragment = <span class="hljs-keyword">new</span> LineComment(comment).compileNode o
<span class="hljs-keyword">if</span> (commentFragment.isHereComment <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> commentFragment.newLine) <span class="hljs-keyword">or</span>
node.includeCommentFragments()</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>Inline block comments, like <code>1 + /* comment */ 2</code>, or a node whose
<code>compileToFragments</code> method has logic for outputting comments.</p>
</div>
<div class="content"><div class='highlight'><pre> unshiftCommentFragment commentFragment
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> commentFragment.unshift
fragments[<span class="hljs-number">0</span>].precedingComments ?= []
fragments[<span class="hljs-number">0</span>].precedingComments.push commentFragment
<span class="hljs-keyword">else</span>
fragments[fragments.length - <span class="hljs-number">1</span>].followingComments ?= []
fragments[fragments.length - <span class="hljs-number">1</span>].followingComments.push commentFragment
fragments</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>If the code generation wishes to use the result of a complex expression
in multiple places, ensure that the expression is only ever evaluated once,
by assigning it to a temporary variable. Pass a level to precompile.</p>
<p>If <code>level</code> is passed, then returns <code>[val, ref]</code>, where <code>val</code> is the compiled value, and <code>ref</code>
is the compiled reference. If <code>level</code> is not passed, this returns <code>[val, ref]</code> where
the two values are raw nodes which have not been compiled.</p>
</div>
<div class="content"><div class='highlight'><pre> cache: <span class="hljs-function"><span class="hljs-params">(o, level, shouldCache)</span> -&gt;</span>
complex = <span class="hljs-keyword">if</span> shouldCache? <span class="hljs-keyword">then</span> shouldCache <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> @shouldCache()
<span class="hljs-keyword">if</span> complex
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
sub = <span class="hljs-keyword">new</span> Assign ref, <span class="hljs-keyword">this</span>
<span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> [sub.compileToFragments(o, level), [@makeCode(ref.value)]] <span class="hljs-keyword">else</span> [sub, ref]
<span class="hljs-keyword">else</span>
ref = <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> @compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span>
[ref, ref]</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>Occasionally it may be useful to make an expression behave as if it was hoisted, whereby the
result of the expression is available before its location in the source, but the expressions
variable scope corresponds the source position. This is used extensively to deal with executable
class bodies in classes.</p>
<p>Calling this method mutates the node, proxying the <code>compileNode</code> and <code>compileToFragments</code>
methods to store their result for later replacing the <code>target</code> node, which is returned by the
call.</p>
</div>
<div class="content"><div class='highlight'><pre> hoist: <span class="hljs-function">-&gt;</span>
@hoisted = <span class="hljs-literal">yes</span>
target = <span class="hljs-keyword">new</span> HoistTarget @
compileNode = @compileNode
compileToFragments = @compileToFragments
@compileNode = <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
target.update compileNode, o
@compileToFragments = <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
target.update compileToFragments, o
target
cacheToCodeFragments: <span class="hljs-function"><span class="hljs-params">(cacheValues)</span> -&gt;</span>
[fragmentsToText(cacheValues[<span class="hljs-number">0</span>]), fragmentsToText(cacheValues[<span class="hljs-number">1</span>])]</pre></div></div>
</li>
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>Construct a node that returns the current nodes result.
Note that this is overridden for smarter behavior for
many statement nodes (e.g. If, For)…</p>
</div>
<div class="content"><div class='highlight'><pre> makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
me = @unwrapAll()
<span class="hljs-keyword">if</span> res
<span class="hljs-keyword">new</span> Call <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">"<span class="hljs-subst">#{res}</span>.push"</span>), [me]
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Return me</pre></div></div>
</li>
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>Does this node, or any of its children, contain a node of a certain kind?
Recursively traverses down the <em>children</em> nodes and returns the first one
that verifies <code>pred</code>. Otherwise return undefined. <code>contains</code> does not cross
scope boundaries.</p>
</div>
<div class="content"><div class='highlight'><pre> contains: <span class="hljs-function"><span class="hljs-params">(pred)</span> -&gt;</span>
node = <span class="hljs-literal">undefined</span>
@traverseChildren <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(n)</span> -&gt;</span>
<span class="hljs-keyword">if</span> pred n
node = n
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span>
node</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Pull out the last node of a node list.</p>
</div>
<div class="content"><div class='highlight'><pre> lastNode: <span class="hljs-function"><span class="hljs-params">(list)</span> -&gt;</span>
<span class="hljs-keyword">if</span> list.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">else</span> list[list.length - <span class="hljs-number">1</span>]</pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p><code>toString</code> representation of the node, for inspecting the parse tree.
This is what <code>coffee --nodes</code> prints out.</p>
</div>
<div class="content"><div class='highlight'><pre> toString: <span class="hljs-function"><span class="hljs-params">(idt = <span class="hljs-string">''</span>, name = @constructor.name)</span> -&gt;</span>
tree = <span class="hljs-string">'\n'</span> + idt + name
tree += <span class="hljs-string">'?'</span> <span class="hljs-keyword">if</span> @soak
@eachChild (node) -&gt; tree += node.toString idt + TAB
tree</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Passes each child to a function, breaking when the function returns <code>false</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> eachChild: <span class="hljs-function"><span class="hljs-params">(func)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">unless</span> @children
<span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> @children <span class="hljs-keyword">when</span> @[attr]
<span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> flatten [@[attr]]
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> func(child) <span class="hljs-keyword">is</span> <span class="hljs-literal">false</span>
<span class="hljs-keyword">this</span>
traverseChildren: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -&gt;</span>
@eachChild (child) -&gt;
recur = func(child)
child.traverseChildren(crossScope, func) <span class="hljs-keyword">unless</span> recur <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p><code>replaceInContext</code> will traverse children looking for a node for which <code>match</code> returns
true. Once found, the matching node will be replaced by the result of calling <code>replacement</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> replaceInContext: <span class="hljs-function"><span class="hljs-params">(match, replacement)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">unless</span> @children
<span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> @children <span class="hljs-keyword">when</span> children = @[attr]
<span class="hljs-keyword">if</span> Array.isArray children
<span class="hljs-keyword">for</span> child, i <span class="hljs-keyword">in</span> children
<span class="hljs-keyword">if</span> match child
children[i..i] = replacement child, @
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> child.replaceInContext match, replacement
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> match children
@[attr] = replacement children, @
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> children.replaceInContext match, replacement
invert: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span>
unwrapAll: <span class="hljs-function">-&gt;</span>
node = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">until</span> node <span class="hljs-keyword">is</span> node = node.unwrap()
node</pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>Default implementations of the common node properties and methods. Nodes
will override these with custom logic, if needed.</p>
</div>
</li>
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">&#182;</a>
</div>
<p><code>children</code> are the properties to recurse into when tree walking. The
<code>children</code> list <em>is</em> the structure of the AST. The <code>parent</code> pointer, and
the pointer to the <code>children</code> are how you can traverse the tree.</p>
</div>
<div class="content"><div class='highlight'><pre> children: []</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p><code>isStatement</code> has to do with “everything is an expression”. A few things
cant be expressions, such as <code>break</code>. Things that <code>isStatement</code> returns
<code>true</code> for are things that cant be used as expressions. There are some
error messages that come from <code>nodes.coffee</code> due to statements ending up
in expression position.</p>
</div>
<div class="content"><div class='highlight'><pre> isStatement: NO</pre></div></div>
</li>
<li id="section-29">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-29">&#182;</a>
</div>
<p>Track comments that have been compiled into fragments, to avoid outputting
them twice.</p>
</div>
<div class="content"><div class='highlight'><pre> compiledComments: []</pre></div></div>
</li>
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#182;</a>
</div>
<p><code>includeCommentFragments</code> lets <code>compileCommentFragments</code> know whether this node
has special awareness of how to handle comments within its output.</p>
</div>
<div class="content"><div class='highlight'><pre> includeCommentFragments: NO</pre></div></div>
</li>
<li id="section-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-31">&#182;</a>
</div>
<p><code>jumps</code> tells you if an expression, or an internal part of an expression
has a flow control construct (like <code>break</code>, or <code>continue</code>, or <code>return</code>,
or <code>throw</code>) that jumps out of the normal flow of control and cant be
used as a value. This is important because things like this make no sense;
we have to disallow them.</p>
</div>
<div class="content"><div class='highlight'><pre> jumps: NO</pre></div></div>
</li>
<li id="section-32">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-32">&#182;</a>
</div>
<p>If <code>node.shouldCache() is false</code>, it is safe to use <code>node</code> more than once.
Otherwise you need to store the value of <code>node</code> in a variable and output
that variable several times instead. Kind of like this: <code>5</code> need not be
cached. <code>returnFive()</code>, however, could have side effects as a result of
evaluating it more than once, and therefore we need to cache it. The
parameter is named <code>shouldCache</code> rather than <code>mustCache</code> because there are
also cases where we might not need to cache but where we want to, for
example a long expression that may well be idempotent but we want to cache
for brevity.</p>
</div>
<div class="content"><div class='highlight'><pre> shouldCache: YES
isChainable: NO
isAssignable: NO
isNumber: NO
unwrap: THIS
unfoldSoak: NO</pre></div></div>
</li>
<li id="section-33">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-33">&#182;</a>
</div>
<p>Is this node used to assign a certain variable?</p>
</div>
<div class="content"><div class='highlight'><pre> assigns: NO</pre></div></div>
</li>
<li id="section-34">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-34">&#182;</a>
</div>
<p>For this node and all descendents, set the location data to <code>locationData</code>
if the location data is not already set.</p>
</div>
<div class="content"><div class='highlight'><pre> updateLocationDataIfMissing: <span class="hljs-function"><span class="hljs-params">(locationData)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @locationData <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @forceUpdateLocation
<span class="hljs-keyword">delete</span> @forceUpdateLocation
@locationData = locationData
@eachChild (child) -&gt;
child.updateLocationDataIfMissing locationData</pre></div></div>
</li>
<li id="section-35">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-35">&#182;</a>
</div>
<p>Throw a SyntaxError associated with this nodes location.</p>
</div>
<div class="content"><div class='highlight'><pre> error: <span class="hljs-function"><span class="hljs-params">(message)</span> -&gt;</span>
throwSyntaxError message, @locationData
makeCode: <span class="hljs-function"><span class="hljs-params">(code)</span> -&gt;</span>
<span class="hljs-keyword">new</span> CodeFragment <span class="hljs-keyword">this</span>, code
wrapInParentheses: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">'('</span>), fragments..., @makeCode(<span class="hljs-string">')'</span>)]
wrapInBraces: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">'{'</span>), fragments..., @makeCode(<span class="hljs-string">'}'</span>)]</pre></div></div>
</li>
<li id="section-36">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-36">&#182;</a>
</div>
<p><code>fragmentsList</code> is an array of arrays of fragments. Each array in fragmentsList will be
concatenated together, with <code>joinStr</code> added in between each, to produce a final flat array
of fragments.</p>
</div>
<div class="content"><div class='highlight'><pre> joinFragmentArrays: <span class="hljs-function"><span class="hljs-params">(fragmentsList, joinStr)</span> -&gt;</span>
answer = []
<span class="hljs-keyword">for</span> fragments, i <span class="hljs-keyword">in</span> fragmentsList
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push @makeCode joinStr
answer = answer.concat fragments
answer</pre></div></div>
</li>
<li id="section-37">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-37">&#182;</a>
</div>
<h3 id="hoisttarget">HoistTarget</h3>
</div>
</li>
<li id="section-38">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-38">&#182;</a>
</div>
<p>A <strong>HoistTargetNode</strong> represents the output location in the node tree for a hoisted node.
See Base#hoist.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.HoistTarget = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HoistTarget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span></pre></div></div>
</li>
<li id="section-39">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-39">&#182;</a>
</div>
<p>Expands hoisted fragments in the given array</p>
</div>
<div class="content"><div class='highlight'><pre> @expand = <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
<span class="hljs-keyword">for</span> fragment, i <span class="hljs-keyword">in</span> fragments <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span> <span class="hljs-keyword">when</span> fragment.fragments
fragments[i..i] = @expand fragment.fragments
fragments
constructor: <span class="hljs-function"><span class="hljs-params">(@source)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()</pre></div></div>
</li>
<li id="section-40">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-40">&#182;</a>
</div>
<p>Holds presentational options to apply when the source node is compiled.</p>
</div>
<div class="content"><div class='highlight'><pre> @options = {}</pre></div></div>
</li>
<li id="section-41">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-41">&#182;</a>
</div>
<p>Placeholder fragments to be replaced by the source nodes compilation.</p>
</div>
<div class="content"><div class='highlight'><pre> @targetFragments = { fragments: [] }
isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@source.isStatement o</pre></div></div>
</li>
<li id="section-42">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-42">&#182;</a>
</div>
<p>Update the target fragments with the result of compiling the source.
Calls the given compile function with the node and options (overriden with the target
presentational options).</p>
</div>
<div class="content"><div class='highlight'><pre> update: <span class="hljs-function"><span class="hljs-params">(compile, o)</span> -&gt;</span>
@targetFragments.fragments = compile.call @source, merge o, @options</pre></div></div>
</li>
<li id="section-43">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-43">&#182;</a>
</div>
<p>Copies the target indent and level, and returns the placeholder fragments</p>
</div>
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
@options.indent = o.indent
@options.level = level ? o.level
[ @targetFragments ]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@compileToFragments o
compileClosure: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@compileToFragments o</pre></div></div>
</li>
<li id="section-44">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-44">&#182;</a>
</div>
<h3 id="block">Block</h3>
</div>
</li>
<li id="section-45">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-45">&#182;</a>
</div>
<p>The block is the list of expressions that forms the body of an
indented block of code the implementation of a function, a clause in an
<code>if</code>, <code>switch</code>, or <code>try</code>, and so on…</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Block = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Block</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@expressions = compact flatten nodes <span class="hljs-keyword">or</span> []
children: [<span class="hljs-string">'expressions'</span>]</pre></div></div>
</li>
<li id="section-46">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-46">&#182;</a>
</div>
<p>Tack an expression on to the end of this expression list.</p>
</div>
<div class="content"><div class='highlight'><pre> push: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
@expressions.push node
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-47">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-47">&#182;</a>
</div>
<p>Remove and return the last expression of this expression list.</p>
</div>
<div class="content"><div class='highlight'><pre> pop: <span class="hljs-function">-&gt;</span>
@expressions.pop()</pre></div></div>
</li>
<li id="section-48">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-48">&#182;</a>
</div>
<p>Add an expression at the beginning of this expression list.</p>
</div>
<div class="content"><div class='highlight'><pre> unshift: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
@expressions.unshift node
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-49">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-49">&#182;</a>
</div>
<p>If this Block consists of just a single node, unwrap it by pulling
it back out.</p>
</div>
<div class="content"><div class='highlight'><pre> unwrap: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @expressions.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> @expressions[<span class="hljs-number">0</span>] <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-50">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-50">&#182;</a>
</div>
<p>Is this an empty block of code?</p>
</div>
<div class="content"><div class='highlight'><pre> isEmpty: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @expressions.length
isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">for</span> exp <span class="hljs-keyword">in</span> @expressions <span class="hljs-keyword">when</span> exp.isStatement o
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-literal">no</span>
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">for</span> exp <span class="hljs-keyword">in</span> @expressions
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = exp.jumps o</pre></div></div>
</li>
<li id="section-51">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-51">&#182;</a>
</div>
<p>A Block node does not return its entire body, rather it
ensures that the final expression is returned.</p>
</div>
<div class="content"><div class='highlight'><pre> makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
len = @expressions.length
<span class="hljs-keyword">while</span> len--
expr = @expressions[len]
@expressions[len] = expr.makeReturn res
@expressions.splice(len, <span class="hljs-number">1</span>) <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> expr.expression
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-52">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-52">&#182;</a>
</div>
<p>A <strong>Block</strong> is the only node that can serve as the root.</p>
</div>
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o = {}, level)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.scope <span class="hljs-keyword">then</span> <span class="hljs-keyword">super</span> o, level <span class="hljs-keyword">else</span> @compileRoot o</pre></div></div>
</li>
<li id="section-53">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-53">&#182;</a>
</div>
<p>Compile all expressions within the <strong>Block</strong> body. If we need to return
the result, and its an expression, simply return it. If its a statement,
ask the statement to do so.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@tab = o.indent
top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP
compiledNodes = []
<span class="hljs-keyword">for</span> node, index <span class="hljs-keyword">in</span> @expressions
<span class="hljs-keyword">if</span> node.hoisted</pre></div></div>
</li>
<li id="section-54">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-54">&#182;</a>
</div>
<p>This is a hoisted expression.
We want to compile this and ignore the result.</p>
</div>
<div class="content"><div class='highlight'><pre> node.compileToFragments o
<span class="hljs-keyword">continue</span>
node = (node.unfoldSoak(o) <span class="hljs-keyword">or</span> node)
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Block</pre></div></div>
</li>
<li id="section-55">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-55">&#182;</a>
</div>
<p>This is a nested block. We dont do anything special here like
enclose it in a new scope; we just compile the statements in this
block along with our own.</p>
</div>
<div class="content"><div class='highlight'><pre> compiledNodes.push node.compileNode o
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> top
node.front = <span class="hljs-literal">yes</span>
fragments = node.compileToFragments o
<span class="hljs-keyword">unless</span> node.isStatement o
fragments = indentInitial fragments, @
[..., lastFragment] = fragments
<span class="hljs-keyword">unless</span> lastFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">''</span> <span class="hljs-keyword">or</span> lastFragment.isComment
fragments.push @makeCode <span class="hljs-string">';'</span>
compiledNodes.push fragments
<span class="hljs-keyword">else</span>
compiledNodes.push node.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">if</span> top
<span class="hljs-keyword">if</span> @spaced
<span class="hljs-keyword">return</span> [].concat @joinFragmentArrays(compiledNodes, <span class="hljs-string">'\n\n'</span>), @makeCode(<span class="hljs-string">'\n'</span>)
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> @joinFragmentArrays(compiledNodes, <span class="hljs-string">'\n'</span>)
<span class="hljs-keyword">if</span> compiledNodes.length
answer = @joinFragmentArrays(compiledNodes, <span class="hljs-string">', '</span>)
<span class="hljs-keyword">else</span>
answer = [@makeCode <span class="hljs-string">'void 0'</span>]
<span class="hljs-keyword">if</span> compiledNodes.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> o.level &gt;= LEVEL_LIST <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer</pre></div></div>
</li>
<li id="section-56">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-56">&#182;</a>
</div>
<p>If we happen to be the top-level <strong>Block</strong>, wrap everything in a safety
closure, unless requested not to. It would be better not to generate them
in the first place, but for now, clean up obvious double-parentheses.</p>
</div>
<div class="content"><div class='highlight'><pre> compileRoot: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.indent = <span class="hljs-keyword">if</span> o.bare <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> TAB
o.level = LEVEL_TOP
@spaced = <span class="hljs-literal">yes</span>
o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-literal">null</span>, o.referencedVars ? []</pre></div></div>
</li>
<li id="section-57">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-57">&#182;</a>
</div>
<p>Mark given local variables in the root scope as parameters so they dont
end up being declared on this block.</p>
</div>
<div class="content"><div class='highlight'><pre> o.scope.parameter name <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> o.locals <span class="hljs-keyword">or</span> []
fragments = @compileWithDeclarations o
HoistTarget.expand fragments
fragments = @compileComments fragments
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> o.bare
[].concat @makeCode(<span class="hljs-string">"(function() {\n"</span>), fragments, @makeCode(<span class="hljs-string">"\n}).call(this);\n"</span>)</pre></div></div>
</li>
<li id="section-58">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-58">&#182;</a>
</div>
<p>Compile the expressions body for the contents of a function, with
declarations of all inner variables pushed up to the top.</p>
</div>
<div class="content"><div class='highlight'><pre> compileWithDeclarations: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragments = []
post = []
<span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> @expressions
exp = exp.unwrap()
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp <span class="hljs-keyword">instanceof</span> Literal
o = merge(o, level: LEVEL_TOP)
<span class="hljs-keyword">if</span> i
rest = @expressions.splice i, <span class="hljs-number">9e9</span>
[spaced, @spaced] = [@spaced, <span class="hljs-literal">no</span>]
[fragments, @spaced] = [@compileNode(o), spaced]
@expressions = rest
post = @compileNode o
{scope} = o
<span class="hljs-keyword">if</span> scope.expressions <span class="hljs-keyword">is</span> <span class="hljs-keyword">this</span>
declars = o.scope.hasDeclarations()
assigns = scope.hasAssignments
<span class="hljs-keyword">if</span> declars <span class="hljs-keyword">or</span> assigns
fragments.push @makeCode <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> i
fragments.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>var "</span>
<span class="hljs-keyword">if</span> declars
declaredVariables = scope.declaredVariables()
<span class="hljs-keyword">for</span> declaredVariable, declaredVariablesIndex <span class="hljs-keyword">in</span> declaredVariables
fragments.push @makeCode declaredVariable
<span class="hljs-keyword">if</span> Object::hasOwnProperty.call o.scope.comments, declaredVariable
fragments.push o.scope.comments[declaredVariable]...
<span class="hljs-keyword">if</span> declaredVariablesIndex <span class="hljs-keyword">isnt</span> declaredVariables.length - <span class="hljs-number">1</span>
fragments.push @makeCode <span class="hljs-string">', '</span>
<span class="hljs-keyword">if</span> assigns
fragments.push @makeCode <span class="hljs-string">",\n<span class="hljs-subst">#{@tab + TAB}</span>"</span> <span class="hljs-keyword">if</span> declars
fragments.push @makeCode scope.assignedVariables().join(<span class="hljs-string">",\n<span class="hljs-subst">#{@tab + TAB}</span>"</span>)
fragments.push @makeCode <span class="hljs-string">";\n<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @spaced <span class="hljs-keyword">then</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">and</span> post.length
fragments.push @makeCode <span class="hljs-string">"\n"</span>
fragments.concat post
compileComments: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments</pre></div></div>
</li>
<li id="section-59">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-59">&#182;</a>
</div>
<p>Insert comments into the output at the next or previous newline.
If there are no newlines at which to place comments, create them.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.precedingComments</pre></div></div>
</li>
<li id="section-60">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-60">&#182;</a>
</div>
<p>Determine the indentation level of the fragment that we are about
to insert comments before, and use that indentation level for our
inserted comments. At this point, the fragments <code>code</code> property
is the generated output JavaScript, and CoffeeScript always
generates output indented by two spaces; so all we need to do is
search for a <code>code</code> property that begins with at least two spaces.</p>
</div>
<div class="content"><div class='highlight'><pre> fragmentIndent = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> pastFragment <span class="hljs-keyword">in</span> fragments[<span class="hljs-number">0.</span>..(fragmentIndex + <span class="hljs-number">1</span>)] <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
indent = <span class="hljs-regexp">/^ {2,}/m</span>.exec pastFragment.code
<span class="hljs-keyword">if</span> indent
fragmentIndent = indent[<span class="hljs-number">0</span>]
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> pastFragment.code
<span class="hljs-keyword">break</span>
code = <span class="hljs-string">"\n<span class="hljs-subst">#{fragmentIndent}</span>"</span> + (
<span class="hljs-keyword">for</span> commentFragment <span class="hljs-keyword">in</span> fragment.precedingComments
<span class="hljs-keyword">if</span> commentFragment.isHereComment <span class="hljs-keyword">and</span> commentFragment.multiline
multident commentFragment.code, fragmentIndent, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
commentFragment.code
).join(<span class="hljs-string">"\n<span class="hljs-subst">#{fragmentIndent}</span>"</span>).replace <span class="hljs-regexp">/^(\s*)$/gm</span>, <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> pastFragment, pastFragmentIndex <span class="hljs-keyword">in</span> fragments[<span class="hljs-number">0.</span>..(fragmentIndex + <span class="hljs-number">1</span>)] <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
newLineIndex = pastFragment.code.lastIndexOf <span class="hljs-string">'\n'</span>
<span class="hljs-keyword">if</span> newLineIndex <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span></pre></div></div>
</li>
<li id="section-61">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-61">&#182;</a>
</div>
<p>Keep searching previous fragments until we cant go back any
further, either because there are no fragments left or weve
discovered that were in a code block that is interpolated
inside a string.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> pastFragmentIndex <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
pastFragment.code = <span class="hljs-string">'\n'</span> + pastFragment.code
newLineIndex = <span class="hljs-number">0</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> pastFragment.isStringWithInterpolations <span class="hljs-keyword">and</span> pastFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">'{'</span>
code = code[<span class="hljs-number">1.</span>.] + <span class="hljs-string">'\n'</span> <span class="hljs-comment"># Move newline to end.</span>
newLineIndex = <span class="hljs-number">1</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">delete</span> fragment.precedingComments
pastFragment.code = pastFragment.code[<span class="hljs-number">0.</span>..newLineIndex] +
code + pastFragment.code[newLineIndex..]
<span class="hljs-keyword">break</span></pre></div></div>
</li>
<li id="section-62">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-62">&#182;</a>
</div>
<p>Yes, this is awfully similar to the previous <code>if</code> block, but if you
look closely youll find lots of tiny differences that make this
confusing if it were abstracted into a function that both blocks share.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.followingComments</pre></div></div>
</li>
<li id="section-63">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-63">&#182;</a>
</div>
<p>Does the first trailing comment follow at the end of a line of code,
like <code>; // Comment</code>, or does it start a new line after a line of code?</p>
</div>
<div class="content"><div class='highlight'><pre> trail = fragment.followingComments[<span class="hljs-number">0</span>].trail
fragmentIndent = <span class="hljs-string">''</span></pre></div></div>
</li>
<li id="section-64">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-64">&#182;</a>
</div>
<p>Find the indent of the next line of code, if we have any non-trailing
comments to output. We need to first find the next newline, as these
comments will be output after that; and then the indent of the line
that follows the next newline.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> trail <span class="hljs-keyword">and</span> fragment.followingComments.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
onNextLine = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> upcomingFragment <span class="hljs-keyword">in</span> fragments[fragmentIndex...]
<span class="hljs-keyword">unless</span> onNextLine
<span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> upcomingFragment.code
onNextLine = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">else</span>
indent = <span class="hljs-regexp">/^ {2,}/m</span>.exec upcomingFragment.code
<span class="hljs-keyword">if</span> indent
fragmentIndent = indent[<span class="hljs-number">0</span>]
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> upcomingFragment.code
<span class="hljs-keyword">break</span></pre></div></div>
</li>
<li id="section-65">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-65">&#182;</a>
</div>
<p>Is this comment following the indent inserted by bare mode?
If so, theres no need to indent this further.</p>
</div>
<div class="content"><div class='highlight'><pre> code = <span class="hljs-keyword">if</span> fragmentIndex <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^\s+$/</span>.test fragments[<span class="hljs-number">0</span>].code
<span class="hljs-string">''</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> trail
<span class="hljs-string">' '</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"\n<span class="hljs-subst">#{fragmentIndent}</span>"</span></pre></div></div>
</li>
<li id="section-66">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-66">&#182;</a>
</div>
<p>Assemble properly indented comments.</p>
</div>
<div class="content"><div class='highlight'><pre> code += (
<span class="hljs-keyword">for</span> commentFragment <span class="hljs-keyword">in</span> fragment.followingComments
<span class="hljs-keyword">if</span> commentFragment.isHereComment <span class="hljs-keyword">and</span> commentFragment.multiline
multident commentFragment.code, fragmentIndent, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
commentFragment.code
).join(<span class="hljs-string">"\n<span class="hljs-subst">#{fragmentIndent}</span>"</span>).replace <span class="hljs-regexp">/^(\s*)$/gm</span>, <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> upcomingFragment, upcomingFragmentIndex <span class="hljs-keyword">in</span> fragments[fragmentIndex...]
newLineIndex = upcomingFragment.code.indexOf <span class="hljs-string">'\n'</span>
<span class="hljs-keyword">if</span> newLineIndex <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span></pre></div></div>
</li>
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-67">&#182;</a>
</div>
<p>Keep searching upcoming fragments until we cant go any
further, either because there are no fragments left or weve
discovered that were in a code block that is interpolated
inside a string.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> upcomingFragmentIndex <span class="hljs-keyword">is</span> fragments.length - <span class="hljs-number">1</span>
upcomingFragment.code = upcomingFragment.code + <span class="hljs-string">'\n'</span>
newLineIndex = upcomingFragment.code.length
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> upcomingFragment.isStringWithInterpolations <span class="hljs-keyword">and</span> upcomingFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">'}'</span>
code = <span class="hljs-string">"<span class="hljs-subst">#{code}</span>\n"</span>
newLineIndex = <span class="hljs-number">0</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">delete</span> fragment.followingComments</pre></div></div>
</li>
<li id="section-68">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-68">&#182;</a>
</div>
<p>Avoid inserting extra blank lines.</p>
</div>
<div class="content"><div class='highlight'><pre> code = code.replace <span class="hljs-regexp">/^\n/</span>, <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> upcomingFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">'\n'</span>
upcomingFragment.code = upcomingFragment.code[<span class="hljs-number">0.</span>..newLineIndex] +
code + upcomingFragment.code[newLineIndex..]
<span class="hljs-keyword">break</span>
fragments</pre></div></div>
</li>
<li id="section-69">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-69">&#182;</a>
</div>
<p>Wrap up the given nodes as a <strong>Block</strong>, unless it already happens
to be one.</p>
</div>
<div class="content"><div class='highlight'><pre> @wrap: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -&gt;</span>
<span class="hljs-keyword">return</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> nodes.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Block
<span class="hljs-keyword">new</span> Block nodes</pre></div></div>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">&#182;</a>
</div>
<h3 id="literal">Literal</h3>
</div>
</li>
<li id="section-71">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-71">&#182;</a>
</div>
<p><code>Literal</code> is a base class for static values that can be passed through
directly into JavaScript without translation, such as: strings, numbers,
<code>true</code>, <code>false</code>, <code>null</code></p>
</div>
<div class="content"><div class='highlight'><pre>exports.Literal = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Literal</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@value)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
shouldCache: NO
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
name <span class="hljs-keyword">is</span> @value
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode @value]
toString: <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-72">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-72">&#182;</a>
</div>
<p>This is only intended for debugging.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isStatement() <span class="hljs-keyword">then</span> <span class="hljs-keyword">super</span>() <span class="hljs-keyword">else</span> @constructor.name}</span>: <span class="hljs-subst">#{@value}</span>"</span>
exports.NumberLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NumberLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.InfinityLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InfinityLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NumberLiteral</span></span>
compileNode: <span class="hljs-function">-&gt;</span>
[@makeCode <span class="hljs-string">'2e308'</span>]
exports.NaNLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NaNLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NumberLiteral</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'NaN'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = [@makeCode <span class="hljs-string">'0/0'</span>]
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_OP <span class="hljs-keyword">then</span> @wrapInParentheses code <span class="hljs-keyword">else</span> code
exports.StringLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
res = <span class="hljs-keyword">if</span> @csx <span class="hljs-keyword">then</span> [@makeCode @unquote(<span class="hljs-literal">yes</span>, <span class="hljs-literal">yes</span>)] <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span>()
unquote: <span class="hljs-function"><span class="hljs-params">(doubleQuote = <span class="hljs-literal">no</span>, newLine = <span class="hljs-literal">no</span>)</span> -&gt;</span>
unquoted = @value[<span class="hljs-number">1.</span>..<span class="hljs-number">-1</span>]
unquoted = unquoted.replace <span class="hljs-regexp">/\\"/g</span>, <span class="hljs-string">'"'</span> <span class="hljs-keyword">if</span> doubleQuote
unquoted = unquoted.replace <span class="hljs-regexp">/\\n/g</span>, <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> newLine
unquoted
exports.RegexLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegexLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.PassthroughLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PassthroughLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.IdentifierLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IdentifierLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isAssignable: YES
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
iterator @
exports.CSXTag = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CSXTag</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">IdentifierLiteral</span></span>
exports.PropertyName = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PropertyName</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isAssignable: YES
exports.ComputedPropertyName = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ComputedPropertyName</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">PropertyName</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">'['</span>), @value.compileToFragments(o, LEVEL_LIST)..., @makeCode(<span class="hljs-string">']'</span>)]
exports.StatementLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StatementLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isStatement: YES
makeReturn: THIS
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">'break'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (o?.<span class="hljs-keyword">loop</span> <span class="hljs-keyword">or</span> o?.block)
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">'continue'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o?.<span class="hljs-keyword">loop</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{@value}</span>;"</span>]
exports.ThisLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThisLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'this'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = <span class="hljs-keyword">if</span> o.scope.method?.bound <span class="hljs-keyword">then</span> o.scope.method.context <span class="hljs-keyword">else</span> @value
[@makeCode code]
exports.UndefinedLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UndefinedLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'undefined'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_ACCESS <span class="hljs-keyword">then</span> <span class="hljs-string">'(void 0)'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'void 0'</span>]
exports.NullLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NullLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'null'</span>
exports.BooleanLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BooleanLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span></pre></div></div>
</li>
<li id="section-73">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-73">&#182;</a>
</div>
<h3 id="return">Return</h3>
</div>
</li>
<li id="section-74">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-74">&#182;</a>
</div>
<p>A <code>return</code> is a <em>pureStatement</em>—wrapping it in a closure wouldnt make sense.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Return = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Return</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'expression'</span>]
isStatement: YES
makeReturn: THIS
jumps: THIS
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
expr = @expression?.makeReturn()
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">and</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">then</span> expr.compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span> o, level
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
answer = []</pre></div></div>
</li>
<li id="section-75">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-75">&#182;</a>
</div>
<p>TODO: If we call <code>expression.compile()</code> here twice, well sometimes
get back different results!</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @expression
answer = @expression.compileToFragments o, LEVEL_PAREN
unshiftAfterComments answer, @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>return "</span></pre></div></div>
</li>
<li id="section-76">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-76">&#182;</a>
</div>
<p>Since the <code>return</code> got indented by <code>@tab</code>, preceding comments that are
multiline need to be indented.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> answer
<span class="hljs-keyword">if</span> fragment.isHereComment <span class="hljs-keyword">and</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> fragment.code
fragment.code = multident fragment.code, @tab
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.isLineComment
fragment.code = <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{fragment.code}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span>
answer.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>return"</span>
answer.push @makeCode <span class="hljs-string">';'</span>
answer</pre></div></div>
</li>
<li id="section-77">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-77">&#182;</a>
</div>
<p><code>yield return</code> works exactly like <code>return</code>, except that it turns the function
into a generator.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.YieldReturn = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">YieldReturn</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Return</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">'yield can only occur inside functions'</span>
<span class="hljs-keyword">super</span> o
exports.AwaitReturn = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AwaitReturn</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Return</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">'await can only occur inside functions'</span>
<span class="hljs-keyword">super</span> o</pre></div></div>
</li>
<li id="section-78">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-78">&#182;</a>
</div>
<h3 id="value">Value</h3>
</div>
</li>
<li id="section-79">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-79">&#182;</a>
</div>
<p>A value, variable or literal or parenthesized, indexed or dotted into,
or vanilla.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Value = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Value</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(base, props, tag, isDefaultValue = <span class="hljs-literal">no</span>)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
<span class="hljs-keyword">return</span> base <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> props <span class="hljs-keyword">and</span> base <span class="hljs-keyword">instanceof</span> Value
@base = base
@properties = props <span class="hljs-keyword">or</span> []
@[tag] = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> tag
@isDefaultValue = isDefaultValue</pre></div></div>
</li>
<li id="section-80">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-80">&#182;</a>
</div>
<p>If this is a <code>@foo =</code> assignment, if there are comments on <code>@</code> move them
to be on <code>foo</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @base?.comments <span class="hljs-keyword">and</span> @base <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">and</span> @properties[<span class="hljs-number">0</span>]?.name?
moveComments @base, @properties[<span class="hljs-number">0</span>].name
children: [<span class="hljs-string">'base'</span>, <span class="hljs-string">'properties'</span>]</pre></div></div>
</li>
<li id="section-81">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-81">&#182;</a>
</div>
<p>Add a property (or <em>properties</em> ) <code>Access</code> to the list.</p>
</div>
<div class="content"><div class='highlight'><pre> add: <span class="hljs-function"><span class="hljs-params">(props)</span> -&gt;</span>
@properties = @properties.concat props
@forceUpdateLocation = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">this</span>
hasProperties: <span class="hljs-function">-&gt;</span>
@properties.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
bareLiteral: <span class="hljs-function"><span class="hljs-params">(type)</span> -&gt;</span>
<span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base <span class="hljs-keyword">instanceof</span> type</pre></div></div>
</li>
<li id="section-82">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-82">&#182;</a>
</div>
<p>Some boolean checks for the benefit of other nodes.</p>
</div>
<div class="content"><div class='highlight'><pre> isArray : <span class="hljs-function">-&gt;</span> @bareLiteral(Arr)
isRange : <span class="hljs-function">-&gt;</span> @bareLiteral(Range)
shouldCache : <span class="hljs-function">-&gt;</span> @hasProperties() <span class="hljs-keyword">or</span> @base.shouldCache()
isAssignable : <span class="hljs-function">-&gt;</span> @hasProperties() <span class="hljs-keyword">or</span> @base.isAssignable()
isNumber : <span class="hljs-function">-&gt;</span> @bareLiteral(NumberLiteral)
isString : <span class="hljs-function">-&gt;</span> @bareLiteral(StringLiteral)
isRegex : <span class="hljs-function">-&gt;</span> @bareLiteral(RegexLiteral)
isUndefined : <span class="hljs-function">-&gt;</span> @bareLiteral(UndefinedLiteral)
isNull : <span class="hljs-function">-&gt;</span> @bareLiteral(NullLiteral)
isBoolean : <span class="hljs-function">-&gt;</span> @bareLiteral(BooleanLiteral)
isAtomic : <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> @properties.concat @base
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> node.soak <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> Call
<span class="hljs-literal">yes</span>
isNotCallable : <span class="hljs-function">-&gt;</span> @isNumber() <span class="hljs-keyword">or</span> @isString() <span class="hljs-keyword">or</span> @isRegex() <span class="hljs-keyword">or</span>
@isArray() <span class="hljs-keyword">or</span> @isRange() <span class="hljs-keyword">or</span> @isSplice() <span class="hljs-keyword">or</span> @isObject() <span class="hljs-keyword">or</span>
@isUndefined() <span class="hljs-keyword">or</span> @isNull() <span class="hljs-keyword">or</span> @isBoolean()
isStatement : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.isStatement o
assigns : <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.assigns name
jumps : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.jumps o
isObject: <span class="hljs-function"><span class="hljs-params">(onlyGenerated)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> @properties.length
(@base <span class="hljs-keyword">instanceof</span> Obj) <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> onlyGenerated <span class="hljs-keyword">or</span> @base.generated)
isElision: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @base <span class="hljs-keyword">instanceof</span> Arr
@base.hasElision()
isSplice: <span class="hljs-function">-&gt;</span>
[..., lastProp] = @properties
lastProp <span class="hljs-keyword">instanceof</span> Slice
looksStatic: <span class="hljs-function"><span class="hljs-params">(className)</span> -&gt;</span>
(@this <span class="hljs-keyword">or</span> @base <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">or</span> @base.value <span class="hljs-keyword">is</span> className) <span class="hljs-keyword">and</span>
@properties.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> @properties[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'prototype'</span></pre></div></div>
</li>
<li id="section-83">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-83">&#182;</a>
</div>
<p>The value can be unwrapped as its inner node, if there are no attached
properties.</p>
</div>
<div class="content"><div class='highlight'><pre> unwrap: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @properties.length <span class="hljs-keyword">then</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> @base</pre></div></div>
</li>
<li id="section-84">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-84">&#182;</a>
</div>
<p>A reference has base part (<code>this</code> value) and name part.
We cache them separately for compiling complex expressions.
<code>a()[b()] ?= c</code> -&gt; <code>(_base = a())[_name = b()] ? _base[_name] = c</code></p>
</div>
<div class="content"><div class='highlight'><pre> cacheReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[..., name] = @properties
<span class="hljs-keyword">if</span> @properties.length &lt; <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @base.shouldCache() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> name?.shouldCache()
<span class="hljs-keyword">return</span> [<span class="hljs-keyword">this</span>, <span class="hljs-keyword">this</span>] <span class="hljs-comment"># `a` `a.b`</span>
base = <span class="hljs-keyword">new</span> Value @base, @properties[...<span class="hljs-number">-1</span>]
<span class="hljs-keyword">if</span> base.shouldCache() <span class="hljs-comment"># `a().b`</span>
bref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'base'</span>
base = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign bref, base
<span class="hljs-keyword">return</span> [base, bref] <span class="hljs-keyword">unless</span> name <span class="hljs-comment"># `a()`</span>
<span class="hljs-keyword">if</span> name.shouldCache() <span class="hljs-comment"># `a[b()]`</span>
nref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'name'</span>
name = <span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> Assign nref, name.index
nref = <span class="hljs-keyword">new</span> Index nref
[base.add(name), <span class="hljs-keyword">new</span> Value(bref <span class="hljs-keyword">or</span> base.base, [nref <span class="hljs-keyword">or</span> name])]</pre></div></div>
</li>
<li id="section-85">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-85">&#182;</a>
</div>
<p>We compile a value to JavaScript by compiling and joining each property.
Things get much more interesting if the chain of properties has <em>soak</em>
operators <code>?.</code> interspersed. Then we have to take care not to accidentally
evaluate anything twice when building the soak chain.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@base.front = @front
props = @properties
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> @base.cached?</pre></div></div>
</li>
<li id="section-86">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-86">&#182;</a>
</div>
<p>Cached fragments enable correct order of the compilation,
and reuse of variables in the scope.
Example:
<code>a(x = 5).b(-&gt; x = 6)</code> should compile in the same order as
<code>a(x = 5); b(-&gt; x = 6)</code>
(see issue #4437, <a href="https://github.com/jashkenas/coffeescript/issues/4437">https://github.com/jashkenas/coffeescript/issues/4437</a>)</p>
</div>
<div class="content"><div class='highlight'><pre> fragments = @base.cached
<span class="hljs-keyword">else</span>
fragments = @base.compileToFragments o, (<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">then</span> LEVEL_ACCESS <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>)
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> SIMPLENUM.test fragmentsToText fragments
fragments.push @makeCode <span class="hljs-string">'.'</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props
fragments.push (prop.compileToFragments o)...
fragments</pre></div></div>
</li>
<li id="section-87">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-87">&#182;</a>
</div>
<p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -&gt; <code>a.b if a?</code></p>
</div>
<div class="content"><div class='highlight'><pre> unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@unfoldedSoak ?= <span class="hljs-keyword">do</span> =&gt;
ifn = @base.unfoldSoak o
<span class="hljs-keyword">if</span> ifn
ifn.body.properties.push @properties...
<span class="hljs-keyword">return</span> ifn
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop.soak
prop.soak = <span class="hljs-literal">off</span>
fst = <span class="hljs-keyword">new</span> Value @base, @properties[...i]
snd = <span class="hljs-keyword">new</span> Value @base, @properties[i..]
<span class="hljs-keyword">if</span> fst.shouldCache()
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
fst = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign ref, fst
snd.base = ref
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If <span class="hljs-keyword">new</span> Existence(fst), snd, soak: <span class="hljs-literal">on</span>
<span class="hljs-literal">no</span>
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @hasProperties()
iterator @
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @base.isAssignable()
@base.eachName iterator
<span class="hljs-keyword">else</span>
@error <span class="hljs-string">'tried to assign to unassignable value'</span></pre></div></div>
</li>
<li id="section-88">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-88">&#182;</a>
</div>
<h3 id="herecomment">HereComment</h3>
</div>
</li>
<li id="section-89">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-89">&#182;</a>
</div>
<p>Comment delimited by <code>###</code> (becoming <code>/* */</code>).</p>
</div>
<div class="content"><div class='highlight'><pre>exports.HereComment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HereComment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({ @content, @newLine, @unshift })</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
multiline = <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> @content
hasLeadingMarks = <span class="hljs-regexp">/\n\s*[#|\*]/</span>.test @content
@content = @content.replace <span class="hljs-regexp">/^([ \t]*)#(?=\s)/gm</span>, <span class="hljs-string">' *'</span> <span class="hljs-keyword">if</span> hasLeadingMarks</pre></div></div>
</li>
<li id="section-90">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-90">&#182;</a>
</div>
<p>Unindent multiline comments. They will be reindented later.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> multiline
largestIndent = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> @content.split <span class="hljs-string">'\n'</span>
leadingWhitespace = <span class="hljs-regexp">/^\s*/</span>.exec(line)[<span class="hljs-number">0</span>]
<span class="hljs-keyword">if</span> leadingWhitespace.length &gt; largestIndent.length
largestIndent = leadingWhitespace
@content = @content.replace <span class="hljs-regexp">///^(<span class="hljs-subst">#{leadingWhitespace}</span>)///</span>gm, <span class="hljs-string">''</span>
@content = <span class="hljs-string">"/*<span class="hljs-subst">#{@content}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> hasLeadingMarks <span class="hljs-keyword">then</span> <span class="hljs-string">' '</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>*/"</span>
fragment = @makeCode @content
fragment.newLine = @newLine
fragment.unshift = @unshift
fragment.multiline = multiline</pre></div></div>
</li>
<li id="section-91">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-91">&#182;</a>
</div>
<p>Dont rely on <code>fragment.type</code>, which can break when the compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> fragment.isComment = fragment.isHereComment = <span class="hljs-literal">yes</span>
fragment</pre></div></div>
</li>
<li id="section-92">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-92">&#182;</a>
</div>
<h3 id="linecomment">LineComment</h3>
</div>
</li>
<li id="section-93">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-93">&#182;</a>
</div>
<p>Comment running from <code>#</code> to the end of a line (becoming <code>//</code>).</p>
</div>
<div class="content"><div class='highlight'><pre>exports.LineComment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LineComment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({ @content, @newLine, @unshift })</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragment = @makeCode(<span class="hljs-keyword">if</span> <span class="hljs-regexp">/^\s*$/</span>.test @content <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"//<span class="hljs-subst">#{@content}</span>"</span>)
fragment.newLine = @newLine
fragment.unshift = @unshift
fragment.trail = <span class="hljs-keyword">not</span> @newLine <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @unshift</pre></div></div>
</li>
<li id="section-94">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-94">&#182;</a>
</div>
<p>Dont rely on <code>fragment.type</code>, which can break when the compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> fragment.isComment = fragment.isLineComment = <span class="hljs-literal">yes</span>
fragment</pre></div></div>
</li>
<li id="section-95">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-95">&#182;</a>
</div>
<h3 id="call">Call</h3>
</div>
</li>
<li id="section-96">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-96">&#182;</a>
</div>
<p>Node for a function invocation.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Call = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Call</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @args = [], @soak, @token)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@isNew = <span class="hljs-literal">no</span>
<span class="hljs-keyword">if</span> @variable <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @variable.isNotCallable()
@variable.error <span class="hljs-string">"literal is not a function"</span>
@csx = @variable.base <span class="hljs-keyword">instanceof</span> CSXTag</pre></div></div>
</li>
<li id="section-97">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-97">&#182;</a>
</div>
<p><code>@variable</code> never gets output as a result of this node getting created as
part of <code>RegexWithInterpolations</code>, so for that case move any comments to
the <code>args</code> property that gets passed into <code>RegexWithInterpolations</code> via
the grammar.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @variable.base?.value <span class="hljs-keyword">is</span> <span class="hljs-string">'RegExp'</span> <span class="hljs-keyword">and</span> @args.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
moveComments @variable, @args[<span class="hljs-number">0</span>]
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'args'</span>]</pre></div></div>
</li>
<li id="section-98">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-98">&#182;</a>
</div>
<p>When setting the location, we sometimes need to update the start location to
account for a newly-discovered <code>new</code> operator to the left of us. This
expands the range on the left, but not the right.</p>
</div>
<div class="content"><div class='highlight'><pre> updateLocationDataIfMissing: <span class="hljs-function"><span class="hljs-params">(locationData)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @locationData <span class="hljs-keyword">and</span> @needsUpdatedStartLocation
@locationData.first_line = locationData.first_line
@locationData.first_column = locationData.first_column
base = @variable?.base <span class="hljs-keyword">or</span> @variable
<span class="hljs-keyword">if</span> base.needsUpdatedStartLocation
@variable.locationData.first_line = locationData.first_line
@variable.locationData.first_column = locationData.first_column
base.updateLocationDataIfMissing locationData
<span class="hljs-keyword">delete</span> @needsUpdatedStartLocation
<span class="hljs-keyword">super</span> locationData</pre></div></div>
</li>
<li id="section-99">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-99">&#182;</a>
</div>
<p>Tag this invocation as creating a new instance.</p>
</div>
<div class="content"><div class='highlight'><pre> newInstance: <span class="hljs-function">-&gt;</span>
base = @variable?.base <span class="hljs-keyword">or</span> @variable
<span class="hljs-keyword">if</span> base <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> base.isNew
base.newInstance()
<span class="hljs-keyword">else</span>
@isNew = <span class="hljs-literal">true</span>
@needsUpdatedStartLocation = <span class="hljs-literal">true</span>
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-100">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-100">&#182;</a>
</div>
<p>Soaked chained invocations unfold into if/else ternary structures.</p>
</div>
<div class="content"><div class='highlight'><pre> unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @soak
<span class="hljs-keyword">if</span> @variable <span class="hljs-keyword">instanceof</span> Super
left = <span class="hljs-keyword">new</span> Literal @variable.compile o
rite = <span class="hljs-keyword">new</span> Value left
@variable.error <span class="hljs-string">"Unsupported reference to 'super'"</span> <span class="hljs-keyword">unless</span> @variable.accessor?
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> ifn <span class="hljs-keyword">if</span> ifn = unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'variable'</span>
[left, rite] = <span class="hljs-keyword">new</span> Value(@variable).cacheReference o
rite = <span class="hljs-keyword">new</span> Call rite, @args
rite.isNew = @isNew
left = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"typeof <span class="hljs-subst">#{ left.compile o }</span> === \"function\""</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If left, <span class="hljs-keyword">new</span> Value(rite), soak: <span class="hljs-literal">yes</span>
call = <span class="hljs-keyword">this</span>
list = []
<span class="hljs-keyword">loop</span>
<span class="hljs-keyword">if</span> call.variable <span class="hljs-keyword">instanceof</span> Call
list.push call
call = call.variable
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> call.variable <span class="hljs-keyword">instanceof</span> Value
list.push call
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> (call = call.variable.base) <span class="hljs-keyword">instanceof</span> Call
<span class="hljs-keyword">for</span> call <span class="hljs-keyword">in</span> list.reverse()
<span class="hljs-keyword">if</span> ifn
<span class="hljs-keyword">if</span> call.variable <span class="hljs-keyword">instanceof</span> Call
call.variable = ifn
<span class="hljs-keyword">else</span>
call.variable.base = ifn
ifn = unfoldSoak o, call, <span class="hljs-string">'variable'</span>
ifn</pre></div></div>
</li>
<li id="section-101">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-101">&#182;</a>
</div>
<p>Compile a vanilla function call.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> @compileCSX o <span class="hljs-keyword">if</span> @csx
@variable?.front = @front
compiledArgs = []</pre></div></div>
</li>
<li id="section-102">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#182;</a>
</div>
<p>If variable is <code>Accessor</code> fragments are cached and used later
in <code>Value::compileNode</code> to ensure correct order of the compilation,
and reuse of variables in the scope.
Example:
<code>a(x = 5).b(-&gt; x = 6)</code> should compile in the same order as
<code>a(x = 5); b(-&gt; x = 6)</code>
(see issue #4437, <a href="https://github.com/jashkenas/coffeescript/issues/4437">https://github.com/jashkenas/coffeescript/issues/4437</a>)</p>
</div>
<div class="content"><div class='highlight'><pre> varAccess = @variable?.properties?[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Access
argCode = (arg <span class="hljs-keyword">for</span> arg <span class="hljs-keyword">in</span> (@args || []) <span class="hljs-keyword">when</span> arg <span class="hljs-keyword">instanceof</span> Code)
<span class="hljs-keyword">if</span> argCode.length &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> varAccess <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @variable.base.cached
[cache] = @variable.base.cache o, LEVEL_ACCESS, <span class="hljs-function">-&gt;</span> <span class="hljs-literal">no</span>
@variable.base.cached = cache
<span class="hljs-keyword">for</span> arg, argIndex <span class="hljs-keyword">in</span> @args
<span class="hljs-keyword">if</span> argIndex <span class="hljs-keyword">then</span> compiledArgs.push @makeCode <span class="hljs-string">", "</span>
compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
fragments = []
<span class="hljs-keyword">if</span> @isNew
@variable.error <span class="hljs-string">"Unsupported reference to 'super'"</span> <span class="hljs-keyword">if</span> @variable <span class="hljs-keyword">instanceof</span> Super
fragments.push @makeCode <span class="hljs-string">'new '</span>
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @makeCode(<span class="hljs-string">'('</span>), compiledArgs..., @makeCode(<span class="hljs-string">')'</span>)
fragments
compileCSX: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[attributes, content] = @args
attributes.base.csx = <span class="hljs-literal">yes</span>
content?.base.csx = <span class="hljs-literal">yes</span>
fragments = [@makeCode(<span class="hljs-string">'&lt;'</span>)]
fragments.push (tag = @variable.compileToFragments(o, LEVEL_ACCESS))...
<span class="hljs-keyword">if</span> attributes.base <span class="hljs-keyword">instanceof</span> Arr
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> attributes.base.objects
attr = obj.base
attrProps = attr?.properties <span class="hljs-keyword">or</span> []</pre></div></div>
</li>
<li id="section-103">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
</div>
<p>Catch invalid CSX attributes: <div {a:"b", props} {props} "value" /></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (attr <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">or</span> attr <span class="hljs-keyword">instanceof</span> IdentifierLiteral) <span class="hljs-keyword">or</span> (attr <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> attr.generated <span class="hljs-keyword">and</span> (attrProps.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> (attrProps[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Splat)))
obj.error <span class="hljs-string">"""
Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute.
"""</span>
obj.base.csx = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> obj.base <span class="hljs-keyword">instanceof</span> Obj
fragments.push @makeCode <span class="hljs-string">' '</span>
fragments.push obj.compileToFragments(o, LEVEL_PAREN)...
<span class="hljs-keyword">if</span> content
fragments.push @makeCode(<span class="hljs-string">'&gt;'</span>)
fragments.push content.compileNode(o, LEVEL_LIST)...
fragments.push [@makeCode(<span class="hljs-string">'&lt;/'</span>), tag..., @makeCode(<span class="hljs-string">'&gt;'</span>)]...
<span class="hljs-keyword">else</span>
fragments.push @makeCode(<span class="hljs-string">' /&gt;'</span>)
fragments</pre></div></div>
</li>
<li id="section-104">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#182;</a>
</div>
<h3 id="super">Super</h3>
</div>
</li>
<li id="section-105">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#182;</a>
</div>
<p>Takes care of converting <code>super()</code> calls into calls against the prototypes
function of the same name.
When <code>expressions</code> are set the call will be compiled in such a way that the
expressions are evaluated without altering the return value of the <code>SuperCall</code>
expression.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.SuperCall = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SuperCall</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
children: Call::children.concat [<span class="hljs-string">'expressions'</span>]
isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@expressions?.length <span class="hljs-keyword">and</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span> o <span class="hljs-keyword">unless</span> @expressions?.length
superCall = <span class="hljs-keyword">new</span> Literal fragmentsToText <span class="hljs-keyword">super</span> o
replacement = <span class="hljs-keyword">new</span> Block @expressions.slice()
<span class="hljs-keyword">if</span> o.level &gt; LEVEL_TOP</pre></div></div>
</li>
<li id="section-106">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-106">&#182;</a>
</div>
<p>If we might be in an expression we need to cache and return the result</p>
</div>
<div class="content"><div class='highlight'><pre> [superCall, ref] = superCall.cache o, <span class="hljs-literal">null</span>, YES
replacement.push ref
replacement.unshift superCall
replacement.compileToFragments o, <span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">then</span> o.level <span class="hljs-keyword">else</span> LEVEL_LIST
exports.Super = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Super</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@accessor)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'accessor'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
method = o.scope.namedMethod()
@error <span class="hljs-string">'cannot use super outside of an instance method'</span> <span class="hljs-keyword">unless</span> method?.isMethod
<span class="hljs-keyword">unless</span> method.ctor? <span class="hljs-keyword">or</span> @accessor?
{name, variable} = method
<span class="hljs-keyword">if</span> name.shouldCache() <span class="hljs-keyword">or</span> (name <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">and</span> name.index.isAssignable())
nref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.parent.freeVariable <span class="hljs-string">'name'</span>
name.index = <span class="hljs-keyword">new</span> Assign nref, name.index
@accessor = <span class="hljs-keyword">if</span> nref? <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index nref <span class="hljs-keyword">else</span> name
<span class="hljs-keyword">if</span> @accessor?.name?.comments</pre></div></div>
</li>
<li id="section-107">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-107">&#182;</a>
</div>
<p>A <code>super()</code> call gets compiled to e.g. <code>super.method()</code>, which means
the <code>method</code> property name gets compiled for the first time here, and
again when the <code>method:</code> property of the class gets compiled. Since
this compilation happens first, comments attached to <code>method:</code> would
get incorrectly output near <code>super.method()</code>, when we want them to
get output on the second pass when <code>method:</code> is output. So set them
aside during this compilation pass, and put them back on the object so
that theyre there for the later compilation.</p>
</div>
<div class="content"><div class='highlight'><pre> salvagedComments = @accessor.name.comments
<span class="hljs-keyword">delete</span> @accessor.name.comments
fragments = (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'super'</span>), <span class="hljs-keyword">if</span> @accessor <span class="hljs-keyword">then</span> [ @accessor ] <span class="hljs-keyword">else</span> [])
.compileToFragments o
attachCommentsToNode salvagedComments, @accessor.name <span class="hljs-keyword">if</span> salvagedComments
fragments</pre></div></div>
</li>
<li id="section-108">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-108">&#182;</a>
</div>
<h3 id="regexwithinterpolations">RegexWithInterpolations</h3>
</div>
</li>
<li id="section-109">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-109">&#182;</a>
</div>
<p>Regexes with interpolations are in fact just a variation of a <code>Call</code> (a
<code>RegExp()</code> call to be precise) with a <code>StringWithInterpolations</code> inside.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.RegexWithInterpolations = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegexWithInterpolations</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(args = [])</span> -&gt;</span>
<span class="hljs-keyword">super</span> (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'RegExp'</span>), args, <span class="hljs-literal">false</span></pre></div></div>
</li>
<li id="section-110">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-110">&#182;</a>
</div>
<h3 id="taggedtemplatecall">TaggedTemplateCall</h3>
</div>
<div class="content"><div class='highlight'><pre>
exports.TaggedTemplateCall = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaggedTemplateCall</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(variable, arg, soak)</span> -&gt;</span>
arg = <span class="hljs-keyword">new</span> StringWithInterpolations Block.wrap([ <span class="hljs-keyword">new</span> Value arg ]) <span class="hljs-keyword">if</span> arg <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">super</span> variable, [ arg ], soak
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@variable.compileToFragments(o, LEVEL_ACCESS).concat @args[<span class="hljs-number">0</span>].compileToFragments(o, LEVEL_LIST)</pre></div></div>
</li>
<li id="section-111">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-111">&#182;</a>
</div>
<h3 id="extends">Extends</h3>
</div>
</li>
<li id="section-112">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-112">&#182;</a>
</div>
<p>Node to extend an objects prototype with an ancestor object.
After <code>goog.inherits</code> from the
<a href="https://github.com/google/closure-library/blob/master/closure/goog/base.js">Closure Library</a>.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Extends = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Extends</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@child, @parent)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'child'</span>, <span class="hljs-string">'parent'</span>]</pre></div></div>
</li>
<li id="section-113">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-113">&#182;</a>
</div>
<p>Hooks one constructor into anothers prototype chain.</p>
</div>
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'extend'</span>, o), [@child, @parent]).compileToFragments o</pre></div></div>
</li>
<li id="section-114">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-114">&#182;</a>
</div>
<h3 id="access">Access</h3>
</div>
</li>
<li id="section-115">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-115">&#182;</a>
</div>
<p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for
an access into the objects prototype.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Access = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Access</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@name, tag)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@soak = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'soak'</span>
children: [<span class="hljs-string">'name'</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
name = @name.compileToFragments o
node = @name.unwrap()
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> PropertyName
[@makeCode(<span class="hljs-string">'.'</span>), name...]
<span class="hljs-keyword">else</span>
[@makeCode(<span class="hljs-string">'['</span>), name..., @makeCode(<span class="hljs-string">']'</span>)]
shouldCache: NO</pre></div></div>
</li>
<li id="section-116">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-116">&#182;</a>
</div>
<h3 id="index">Index</h3>
</div>
</li>
<li id="section-117">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-117">&#182;</a>
</div>
<p>A <code>[ ... ]</code> indexed access into an array or object.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Index = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@index)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'index'</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[].concat @makeCode(<span class="hljs-string">"["</span>), @index.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">"]"</span>)
shouldCache: <span class="hljs-function">-&gt;</span>
@index.shouldCache()</pre></div></div>
</li>
<li id="section-118">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-118">&#182;</a>
</div>
<h3 id="range">Range</h3>
</div>
</li>
<li id="section-119">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-119">&#182;</a>
</div>
<p>A range literal. Ranges can be used to extract portions (slices) of arrays,
to specify a range for comprehensions, or as a value, to be expanded into the
corresponding array of integers at runtime.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Range = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Range</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
children: [<span class="hljs-string">'from'</span>, <span class="hljs-string">'to'</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@from, @to, tag)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@exclusive = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'exclusive'</span>
@equals = <span class="hljs-keyword">if</span> @exclusive <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'='</span></pre></div></div>
</li>
<li id="section-120">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-120">&#182;</a>
</div>
<p>Compiles the ranges source variables where it starts and where it ends.
But only if they need to be cached to avoid double evaluation.</p>
</div>
<div class="content"><div class='highlight'><pre> compileVariables: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o = merge o, top: <span class="hljs-literal">true</span>
shouldCache = del o, <span class="hljs-string">'shouldCache'</span>
[@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST, shouldCache
[@toC, @toVar] = @cacheToCodeFragments @to.cache o, LEVEL_LIST, shouldCache
[@step, @stepVar] = @cacheToCodeFragments step.cache o, LEVEL_LIST, shouldCache <span class="hljs-keyword">if</span> step = del o, <span class="hljs-string">'step'</span>
@fromNum = <span class="hljs-keyword">if</span> @from.isNumber() <span class="hljs-keyword">then</span> Number @fromVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>
@toNum = <span class="hljs-keyword">if</span> @to.isNumber() <span class="hljs-keyword">then</span> Number @toVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>
@stepNum = <span class="hljs-keyword">if</span> step?.isNumber() <span class="hljs-keyword">then</span> Number @stepVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-121">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-121">&#182;</a>
</div>
<p>When compiled normally, the range returns the contents of the <em>for loop</em>
needed to iterate over the values in the range. Used by comprehensions.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@compileVariables o <span class="hljs-keyword">unless</span> @fromVar
<span class="hljs-keyword">return</span> @compileArray(o) <span class="hljs-keyword">unless</span> o.index</pre></div></div>
</li>
<li id="section-122">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-122">&#182;</a>
</div>
<p>Set up endpoints.</p>
</div>
<div class="content"><div class='highlight'><pre> known = @fromNum? <span class="hljs-keyword">and</span> @toNum?
idx = del o, <span class="hljs-string">'index'</span>
idxName = del o, <span class="hljs-string">'name'</span>
namedIndex = idxName <span class="hljs-keyword">and</span> idxName <span class="hljs-keyword">isnt</span> idx
varPart =
<span class="hljs-keyword">if</span> known <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> namedIndex
<span class="hljs-string">"var <span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@toC}</span>"</span> <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@step}</span>"</span> <span class="hljs-keyword">if</span> @step <span class="hljs-keyword">isnt</span> @stepVar
[lt, gt] = [<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &lt;<span class="hljs-subst">#{@equals}</span>"</span>, <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &gt;<span class="hljs-subst">#{@equals}</span>"</span>]</pre></div></div>
</li>
<li id="section-123">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-123">&#182;</a>
</div>
<p>Generate the condition.</p>
</div>
<div class="content"><div class='highlight'><pre> [<span class="hljs-keyword">from</span>, to] = [@fromNum, @toNum]</pre></div></div>
</li>
<li id="section-124">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-124">&#182;</a>
</div>
<p>Always check if the <code>step</code> isnt zero to avoid the infinite loop.</p>
</div>
<div class="content"><div class='highlight'><pre> stepNotZero = <span class="hljs-string">"<span class="hljs-subst">#{ @stepNum ? @stepVar }</span> !== 0"</span>
stepCond = <span class="hljs-string">"<span class="hljs-subst">#{ @stepNum ? @stepVar }</span> &gt; 0"</span>
lowerBound = <span class="hljs-string">"<span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{ <span class="hljs-keyword">if</span> known <span class="hljs-keyword">then</span> to <span class="hljs-keyword">else</span> @toVar }</span>"</span>
upperBound = <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{ <span class="hljs-keyword">if</span> known <span class="hljs-keyword">then</span> to <span class="hljs-keyword">else</span> @toVar }</span>"</span>
condPart =
<span class="hljs-keyword">if</span> @step?
<span class="hljs-keyword">if</span> @stepNum? <span class="hljs-keyword">and</span> @stepNum <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> @stepNum &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{lowerBound}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{upperBound}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"<span class="hljs-subst">#{stepNotZero}</span> &amp;&amp; (<span class="hljs-subst">#{stepCond}</span> ? <span class="hljs-subst">#{lowerBound}</span> : <span class="hljs-subst">#{upperBound}</span>)"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> known
<span class="hljs-string">"<span class="hljs-subst">#{ <span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span> &lt;= to <span class="hljs-keyword">then</span> lt <span class="hljs-keyword">else</span> gt }</span> <span class="hljs-subst">#{to}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"(<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span> ? <span class="hljs-subst">#{lowerBound}</span> : <span class="hljs-subst">#{upperBound}</span>)"</span>
cond = <span class="hljs-keyword">if</span> @stepVar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{@stepVar}</span> &gt; 0"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>"</span></pre></div></div>
</li>
<li id="section-125">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-125">&#182;</a>
</div>
<p>Generate the step.</p>
</div>
<div class="content"><div class='highlight'><pre> stepPart = <span class="hljs-keyword">if</span> @stepVar
<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> += <span class="hljs-subst">#{@stepVar}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> known
<span class="hljs-keyword">if</span> namedIndex
<span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span> &lt;= to <span class="hljs-keyword">then</span> <span class="hljs-string">"++<span class="hljs-subst">#{idx}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"--<span class="hljs-subst">#{idx}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span> &lt;= to <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>++"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>--"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> namedIndex
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? ++<span class="hljs-subst">#{idx}</span> : --<span class="hljs-subst">#{idx}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{idx}</span>++ : <span class="hljs-subst">#{idx}</span>--"</span>
varPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{varPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex
stepPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{stepPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex</pre></div></div>
</li>
<li id="section-126">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-126">&#182;</a>
</div>
<p>The final loop body.</p>
</div>
<div class="content"><div class='highlight'><pre> [@makeCode <span class="hljs-string">"<span class="hljs-subst">#{varPart}</span>; <span class="hljs-subst">#{condPart}</span>; <span class="hljs-subst">#{stepPart}</span>"</span>]</pre></div></div>
</li>
<li id="section-127">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-127">&#182;</a>
</div>
<p>When used as a value, expand the range into the equivalent array.</p>
</div>
<div class="content"><div class='highlight'><pre> compileArray: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
known = @fromNum? <span class="hljs-keyword">and</span> @toNum?
<span class="hljs-keyword">if</span> known <span class="hljs-keyword">and</span> Math.abs(@fromNum - @toNum) &lt;= <span class="hljs-number">20</span>
range = [@fromNum..@toNum]
range.pop() <span class="hljs-keyword">if</span> @exclusive
<span class="hljs-keyword">return</span> [@makeCode <span class="hljs-string">"[<span class="hljs-subst">#{ range.join(<span class="hljs-string">', '</span>) }</span>]"</span>]
idt = @tab + TAB
i = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>, reserve: <span class="hljs-literal">no</span>
result = o.scope.freeVariable <span class="hljs-string">'results'</span>, reserve: <span class="hljs-literal">no</span>
pre = <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span>var <span class="hljs-subst">#{result}</span> = [];"</span>
<span class="hljs-keyword">if</span> known
o.index = i
body = fragmentsToText @compileNode o
<span class="hljs-keyword">else</span>
vars = <span class="hljs-string">"<span class="hljs-subst">#{i}</span> = <span class="hljs-subst">#{@fromC}</span>"</span> + <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar <span class="hljs-keyword">then</span> <span class="hljs-string">", <span class="hljs-subst">#{@toC}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
cond = <span class="hljs-string">"<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>"</span>
body = <span class="hljs-string">"var <span class="hljs-subst">#{vars}</span>; <span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{i}</span> &lt;<span class="hljs-subst">#{@equals}</span> <span class="hljs-subst">#{@toVar}</span> : <span class="hljs-subst">#{i}</span> &gt;<span class="hljs-subst">#{@equals}</span> <span class="hljs-subst">#{@toVar}</span>; <span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{i}</span>++ : <span class="hljs-subst">#{i}</span>--"</span>
post = <span class="hljs-string">"{ <span class="hljs-subst">#{result}</span>.push(<span class="hljs-subst">#{i}</span>); }\n<span class="hljs-subst">#{idt}</span>return <span class="hljs-subst">#{result}</span>;\n<span class="hljs-subst">#{o.indent}</span>"</span>
<span class="hljs-function"> <span class="hljs-title">hasArgs</span> = <span class="hljs-params">(node)</span> -&gt;</span> node?.contains isLiteralArguments
args = <span class="hljs-string">', arguments'</span> <span class="hljs-keyword">if</span> hasArgs(@from) <span class="hljs-keyword">or</span> hasArgs(@to)
[@makeCode <span class="hljs-string">"(function() {<span class="hljs-subst">#{pre}</span>\n<span class="hljs-subst">#{idt}</span>for (<span class="hljs-subst">#{body}</span>)<span class="hljs-subst">#{post}</span>}).apply(this<span class="hljs-subst">#{args ? <span class="hljs-string">''</span>}</span>)"</span>]</pre></div></div>
</li>
<li id="section-128">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-128">&#182;</a>
</div>
<h3 id="slice">Slice</h3>
</div>
</li>
<li id="section-129">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-129">&#182;</a>
</div>
<p>An array slice literal. Unlike JavaScripts <code>Array#slice</code>, the second parameter
specifies the index of the end of the slice, just as the first parameter
is the index of the beginning.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Slice = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Slice</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
children: [<span class="hljs-string">'range'</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@range)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()</pre></div></div>
</li>
<li id="section-130">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-130">&#182;</a>
</div>
<p>We have to be careful when trying to slice through the end of the array,
<code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>.
<code>9e9</code> should be safe because <code>9e9</code> &gt; <code>2**32</code>, the max array length.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{to, <span class="hljs-keyword">from</span>} = @range</pre></div></div>
</li>
<li id="section-131">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-131">&#182;</a>
</div>
<p>Handle an expression in the property access, e.g. <code>a[!b in c..]</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span>?.shouldCache()
<span class="hljs-keyword">from</span> = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">from</span>
<span class="hljs-keyword">if</span> to?.shouldCache()
to = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens to
fromCompiled = <span class="hljs-keyword">from</span>?.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">or</span> [@makeCode <span class="hljs-string">'0'</span>]
<span class="hljs-keyword">if</span> to
compiled = to.compileToFragments o, LEVEL_PAREN
compiledText = fragmentsToText compiled
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">not</span> @range.exclusive <span class="hljs-keyword">and</span> +compiledText <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span>)
toStr = <span class="hljs-string">', '</span> + <span class="hljs-keyword">if</span> @range.exclusive
compiledText
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> to.isNumber()
<span class="hljs-string">"<span class="hljs-subst">#{+compiledText + <span class="hljs-number">1</span>}</span>"</span>
<span class="hljs-keyword">else</span>
compiled = to.compileToFragments o, LEVEL_ACCESS
<span class="hljs-string">"+<span class="hljs-subst">#{fragmentsToText compiled}</span> + 1 || 9e9"</span>
[@makeCode <span class="hljs-string">".slice(<span class="hljs-subst">#{ fragmentsToText fromCompiled }</span><span class="hljs-subst">#{ toStr <span class="hljs-keyword">or</span> <span class="hljs-string">''</span> }</span>)"</span>]</pre></div></div>
</li>
<li id="section-132">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-132">&#182;</a>
</div>
<h3 id="obj">Obj</h3>
</div>
</li>
<li id="section-133">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-133">&#182;</a>
</div>
<p>An object literal, nothing fancy.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Obj = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Obj</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(props, @generated = <span class="hljs-literal">no</span>, @lhs = <span class="hljs-literal">no</span>)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@objects = @properties = props <span class="hljs-keyword">or</span> []
children: [<span class="hljs-string">'properties'</span>]
isAssignable: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties</pre></div></div>
</li>
<li id="section-134">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-134">&#182;</a>
</div>
<p>Check for reserved words.</p>
</div>
<div class="content"><div class='highlight'><pre> message = isUnassignable prop.unwrapAll().value
prop.error message <span class="hljs-keyword">if</span> message
prop = prop.value <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span>
prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> <span class="hljs-keyword">and</span>
prop.value?.base <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Arr
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> prop.isAssignable()
<span class="hljs-literal">yes</span>
shouldCache: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @isAssignable()</pre></div></div>
</li>
<li id="section-135">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-135">&#182;</a>
</div>
<p>Check if object contains splat.</p>
</div>
<div class="content"><div class='highlight'><pre> hasSplat: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop <span class="hljs-keyword">instanceof</span> Splat
<span class="hljs-literal">no</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
props = @properties
<span class="hljs-keyword">if</span> @generated
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> node <span class="hljs-keyword">instanceof</span> Value
node.error <span class="hljs-string">'cannot have an implicit value in an implicit object'</span></pre></div></div>
</li>
<li id="section-136">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-136">&#182;</a>
</div>
<p>Object spread properties. <a href="https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md">https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md</a></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> @compileSpread o <span class="hljs-keyword">if</span> @hasSplat() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @csx
idt = o.indent += TAB
lastNode = @lastNode @properties</pre></div></div>
</li>
<li id="section-137">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-137">&#182;</a>
</div>
<p>CSX attributes <div id="val" attr={aaa} {props...} /></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> @compileCSXAttributes o <span class="hljs-keyword">if</span> @csx</pre></div></div>
</li>
<li id="section-138">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-138">&#182;</a>
</div>
<p>If this object is the left-hand side of an assignment, all its children
are too.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @lhs
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> prop <span class="hljs-keyword">instanceof</span> Assign
{value} = prop
unwrappedVal = value.unwrapAll()
<span class="hljs-keyword">if</span> unwrappedVal <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> unwrappedVal <span class="hljs-keyword">instanceof</span> Obj
unwrappedVal.lhs = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> unwrappedVal <span class="hljs-keyword">instanceof</span> Assign
unwrappedVal.nestedLhs = <span class="hljs-literal">yes</span>
isCompact = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
isCompact = <span class="hljs-literal">no</span>
answer = []
answer.push @makeCode <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'\n'</span>
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props
join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span>
<span class="hljs-string">''</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> isCompact
<span class="hljs-string">', '</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">is</span> lastNode
<span class="hljs-string">'\n'</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">',\n'</span>
indent = <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> idt
key = <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
prop.variable
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign
prop.operatorToken.error <span class="hljs-string">"unexpected <span class="hljs-subst">#{prop.operatorToken.value}</span>"</span> <span class="hljs-keyword">unless</span> @lhs
prop.variable
<span class="hljs-keyword">else</span>
prop
<span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> key.hasProperties()
key.error <span class="hljs-string">'invalid object key'</span> <span class="hljs-keyword">if</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> key.<span class="hljs-keyword">this</span>
key = key.properties[<span class="hljs-number">0</span>].name
prop = <span class="hljs-keyword">new</span> Assign key, prop, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> key <span class="hljs-keyword">is</span> prop
<span class="hljs-keyword">if</span> prop.shouldCache()
[key, value] = prop.base.cache o
key = <span class="hljs-keyword">new</span> PropertyName key.value <span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> IdentifierLiteral
prop = <span class="hljs-keyword">new</span> Assign key, value, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> key.base <span class="hljs-keyword">instanceof</span> ComputedPropertyName</pre></div></div>
</li>
<li id="section-139">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-139">&#182;</a>
</div>
<p><code>{ [foo()] }</code> output as <code>{ [ref = foo()]: ref }</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> prop.base.value.shouldCache()
[key, value] = prop.base.value.cache o
key = <span class="hljs-keyword">new</span> ComputedPropertyName key.value <span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> IdentifierLiteral
prop = <span class="hljs-keyword">new</span> Assign key, value, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-140">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-140">&#182;</a>
</div>
<p><code>{ [expression] }</code> output as <code>{ [expression]: expression }</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> prop = <span class="hljs-keyword">new</span> Assign key, prop.base.value, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> prop.bareLiteral?(IdentifierLiteral)
prop = <span class="hljs-keyword">new</span> Assign prop, prop, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> indent <span class="hljs-keyword">then</span> answer.push @makeCode indent
answer.push prop.compileToFragments(o, LEVEL_TOP)...
<span class="hljs-keyword">if</span> join <span class="hljs-keyword">then</span> answer.push @makeCode join
answer.push @makeCode <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>
answer = @wrapInBraces answer
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop.assigns name <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-literal">no</span>
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties
prop = prop.value <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
prop = prop.unwrapAll()
prop.eachName iterator <span class="hljs-keyword">if</span> prop.eachName?</pre></div></div>
</li>
<li id="section-141">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-141">&#182;</a>
</div>
<p>Object spread properties. <a href="https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md">https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md</a>
<code>obj2 = {a: 1, obj..., c: 3, d: 4}</code><code>obj2 = _extends({}, {a: 1}, obj, {c: 3, d: 4})</code></p>
</div>
<div class="content"><div class='highlight'><pre> compileSpread: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
props = @properties</pre></div></div>
</li>
<li id="section-142">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-142">&#182;</a>
</div>
<p>Store object spreads.</p>
</div>
<div class="content"><div class='highlight'><pre> splatSlice = []
propSlices = []
slices = []
<span class="hljs-function"> <span class="hljs-title">addSlice</span> = -&gt;</span>
slices.push <span class="hljs-keyword">new</span> Obj propSlices <span class="hljs-keyword">if</span> propSlices.length
slices.push splatSlice... <span class="hljs-keyword">if</span> splatSlice.length
splatSlice = []
propSlices = []
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Splat
splatSlice.push <span class="hljs-keyword">new</span> Value prop.name
addSlice()
<span class="hljs-keyword">else</span>
propSlices.push prop
addSlice()
slices.unshift <span class="hljs-keyword">new</span> Obj <span class="hljs-keyword">unless</span> slices[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Obj
_extends = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'_extends'</span>, o
(<span class="hljs-keyword">new</span> Call _extends, slices).compileToFragments o
compileCSXAttributes: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
props = @properties
answer = []
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props
prop.csx = <span class="hljs-literal">yes</span>
join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">' '</span>
prop = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"{<span class="hljs-subst">#{prop.compile(o)}</span>}"</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Splat
answer.push prop.compileToFragments(o, LEVEL_TOP)...
answer.push @makeCode join
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer</pre></div></div>
</li>
<li id="section-143">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-143">&#182;</a>
</div>
<h3 id="arr">Arr</h3>
</div>
</li>
<li id="section-144">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-144">&#182;</a>
</div>
<p>An array literal.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Arr = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Arr</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(objs, @lhs = <span class="hljs-literal">no</span>)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@objects = objs <span class="hljs-keyword">or</span> []
children: [<span class="hljs-string">'objects'</span>]
hasElision: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Elision
<span class="hljs-literal">no</span>
isAssignable: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @objects.length
<span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> @objects
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">and</span> i + <span class="hljs-number">1</span> <span class="hljs-keyword">isnt</span> @objects.length
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> obj.isAssignable() <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> obj.isAtomic <span class="hljs-keyword">or</span> obj.isAtomic())
<span class="hljs-literal">yes</span>
shouldCache: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @isAssignable()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> [@makeCode <span class="hljs-string">'[]'</span>] <span class="hljs-keyword">unless</span> @objects.length
o.indent += TAB
<span class="hljs-function"> <span class="hljs-title">fragmentIsElision</span> = <span class="hljs-params">(fragment)</span> -&gt;</span> fragmentsToText(fragment).trim() <span class="hljs-keyword">is</span> <span class="hljs-string">','</span></pre></div></div>
</li>
<li id="section-145">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-145">&#182;</a>
</div>
<p>Detect if <code>Elisions</code> at the beginning of the array are processed (e.g. [, , , a]).</p>
</div>
<div class="content"><div class='highlight'><pre> passedElision = <span class="hljs-literal">no</span>
answer = []
<span class="hljs-keyword">for</span> obj, objIndex <span class="hljs-keyword">in</span> @objects
unwrappedObj = obj.unwrapAll()</pre></div></div>
</li>
<li id="section-146">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-146">&#182;</a>
</div>
<p>Let <code>compileCommentFragments</code> know to intersperse block comments
into the fragments created when compiling this array.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> unwrappedObj.comments <span class="hljs-keyword">and</span>
unwrappedObj.comments.filter(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> <span class="hljs-keyword">not</span> comment.here).length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
unwrappedObj.includeCommentFragments = YES</pre></div></div>
</li>
<li id="section-147">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-147">&#182;</a>
</div>
<p>If this array is the left-hand side of an assignment, all its children
are too.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @lhs
unwrappedObj.lhs = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> unwrappedObj <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> unwrappedObj <span class="hljs-keyword">instanceof</span> Obj
compiledObjs = (obj.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects)
olen = compiledObjs.length</pre></div></div>
</li>
<li id="section-148">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-148">&#182;</a>
</div>
<p>If <code>compiledObjs</code> includes newlines, we will output this as a multiline
array (i.e. with a newline and indentation after the <code>[</code>). If an element
contains line comments, that should also trigger multiline output since
by definition line comments will introduce newlines into our output.
The exception is if only the first element has line comments; in that
case, output as the compact form if we otherwise would have, so that the
first elements line comments get output before or after the array.</p>
</div>
<div class="content"><div class='highlight'><pre> includesLineCommentsOnNonFirstElement = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledObjs
<span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = fragment.code.trim()
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> index <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> includesLineCommentsOnNonFirstElement <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">and</span> hasLineComments fragment
includesLineCommentsOnNonFirstElement = <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-149">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-149">&#182;</a>
</div>
<p>Add , if all <code>Elisions</code> from the beginning of the array are processed (e.g. [, , , a]) and
element isnt <code>Elision</code> or last element is <code>Elision</code> (e.g. [a,,b,,])</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> index <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> passedElision <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> fragmentIsElision(fragments) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">is</span> olen - <span class="hljs-number">1</span>)
answer.push @makeCode <span class="hljs-string">', '</span>
passedElision = passedElision <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> fragmentIsElision fragments
answer.push fragments...
<span class="hljs-keyword">if</span> includesLineCommentsOnNonFirstElement <span class="hljs-keyword">or</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> fragmentsToText(answer)
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> answer
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = <span class="hljs-string">"<span class="hljs-subst">#{multident(fragment.code, o.indent, <span class="hljs-literal">no</span>)}</span>\n<span class="hljs-subst">#{o.indent}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">', '</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> fragment?.isElision
fragment.code = <span class="hljs-string">",\n<span class="hljs-subst">#{o.indent}</span>"</span>
answer.unshift @makeCode <span class="hljs-string">"[\n<span class="hljs-subst">#{o.indent}</span>"</span>
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>]"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> answer <span class="hljs-keyword">when</span> fragment.isHereComment
fragment.code = <span class="hljs-string">"<span class="hljs-subst">#{fragment.code}</span> "</span>
answer.unshift @makeCode <span class="hljs-string">'['</span>
answer.push @makeCode <span class="hljs-string">']'</span>
answer
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects <span class="hljs-keyword">when</span> obj.assigns name <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-literal">no</span>
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects
obj = obj.unwrapAll()
obj.eachName iterator</pre></div></div>
</li>
<li id="section-150">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-150">&#182;</a>
</div>
<h3 id="class">Class</h3>
</div>
</li>
<li id="section-151">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-151">&#182;</a>
</div>
<p>The CoffeeScript class definition.
Initialize a <strong>Class</strong> with its name, an optional superclass, and a body.</p>
</div>
<div class="content"><div class='highlight'><pre>
exports.Class = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'parent'</span>, <span class="hljs-string">'body'</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @parent, @body = <span class="hljs-keyword">new</span> Block)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name = @determineName()
executableBody = @walkBody()</pre></div></div>
</li>
<li id="section-152">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-152">&#182;</a>
</div>
<p>Special handling to allow <code>class expr.A extends A</code> declarations</p>
</div>
<div class="content"><div class='highlight'><pre> parentName = @parent.base.value <span class="hljs-keyword">if</span> @parent <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @parent.hasProperties()
@hasNameClash = @name? <span class="hljs-keyword">and</span> @name <span class="hljs-keyword">is</span> parentName
node = @
<span class="hljs-keyword">if</span> executableBody <span class="hljs-keyword">or</span> @hasNameClash
node = <span class="hljs-keyword">new</span> ExecutableClassBody node, executableBody
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @name? <span class="hljs-keyword">and</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP</pre></div></div>
</li>
<li id="section-153">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-153">&#182;</a>
</div>
<p>Anonymous classes are only valid in expressions</p>
</div>
<div class="content"><div class='highlight'><pre> node = <span class="hljs-keyword">new</span> Parens node
<span class="hljs-keyword">if</span> @boundMethods.length <span class="hljs-keyword">and</span> @parent
@variable ?= <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'_class'</span>
[@variable, @variableRef] = @variable.cache o <span class="hljs-keyword">unless</span> @variableRef?
<span class="hljs-keyword">if</span> @variable
node = <span class="hljs-keyword">new</span> Assign @variable, node, <span class="hljs-literal">null</span>, { @moduleDeclaration }
@compileNode = @compileClassDeclaration
<span class="hljs-keyword">try</span>
<span class="hljs-keyword">return</span> node.compileToFragments o
<span class="hljs-keyword">finally</span>
<span class="hljs-keyword">delete</span> @compileNode
compileClassDeclaration: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@ctor ?= @makeDefaultConstructor() <span class="hljs-keyword">if</span> @externalCtor <span class="hljs-keyword">or</span> @boundMethods.length
@ctor?.noReturn = <span class="hljs-literal">true</span>
@proxyBoundMethods() <span class="hljs-keyword">if</span> @boundMethods.length
o.indent += TAB
result = []
result.push @makeCode <span class="hljs-string">"class "</span>
result.push @makeCode @name <span class="hljs-keyword">if</span> @name
@compileCommentFragments o, @variable, result <span class="hljs-keyword">if</span> @variable?.comments?
result.push @makeCode <span class="hljs-string">' '</span> <span class="hljs-keyword">if</span> @name
result.push @makeCode(<span class="hljs-string">'extends '</span>), @parent.compileToFragments(o)..., @makeCode <span class="hljs-string">' '</span> <span class="hljs-keyword">if</span> @parent
result.push @makeCode <span class="hljs-string">'{'</span>
<span class="hljs-keyword">unless</span> @body.isEmpty()
@body.spaced = <span class="hljs-literal">true</span>
result.push @makeCode <span class="hljs-string">'\n'</span>
result.push @body.compileToFragments(o, LEVEL_TOP)...
result.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>
result.push @makeCode <span class="hljs-string">'}'</span>
result</pre></div></div>
</li>
<li id="section-154">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-154">&#182;</a>
</div>
<p>Figure out the appropriate name for this class</p>
</div>
<div class="content"><div class='highlight'><pre> determineName: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">unless</span> @variable
[..., tail] = @variable.properties
node = <span class="hljs-keyword">if</span> tail
tail <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> tail.name
<span class="hljs-keyword">else</span>
@variable.base
<span class="hljs-keyword">unless</span> node <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> PropertyName
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
name = node.value
<span class="hljs-keyword">unless</span> tail
message = isUnassignable name
@variable.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN <span class="hljs-keyword">then</span> <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">else</span> name
walkBody: <span class="hljs-function">-&gt;</span>
@ctor = <span class="hljs-literal">null</span>
@boundMethods = []
executableBody = <span class="hljs-literal">null</span>
initializer = []
{ expressions } = @body
i = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> expression <span class="hljs-keyword">in</span> expressions.slice()
<span class="hljs-keyword">if</span> expression <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expression.isObject <span class="hljs-literal">true</span>
{ properties } = expression.base
exprs = []
end = <span class="hljs-number">0</span>
start = <span class="hljs-number">0</span>
<span class="hljs-function"> <span class="hljs-title">pushSlice</span> = -&gt;</span> exprs.push <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Obj properties[start...end], <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> end &gt; start
<span class="hljs-keyword">while</span> assign = properties[end]
<span class="hljs-keyword">if</span> initializerExpression = @addInitializerExpression assign
pushSlice()
exprs.push initializerExpression
initializer.push initializerExpression
start = end + <span class="hljs-number">1</span>
end++
pushSlice()
expressions[i..i] = exprs
i += exprs.length
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> initializerExpression = @addInitializerExpression expression
initializer.push initializerExpression
expressions[i] = initializerExpression
i += <span class="hljs-number">1</span>
<span class="hljs-keyword">for</span> method <span class="hljs-keyword">in</span> initializer <span class="hljs-keyword">when</span> method <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">if</span> method.ctor
method.error <span class="hljs-string">'Cannot define more than one constructor in a class'</span> <span class="hljs-keyword">if</span> @ctor
@ctor = method
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method.isStatic <span class="hljs-keyword">and</span> method.bound
method.context = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method.bound
@boundMethods.push method
<span class="hljs-keyword">if</span> initializer.length <span class="hljs-keyword">isnt</span> expressions.length
@body.expressions = (expression.hoist() <span class="hljs-keyword">for</span> expression <span class="hljs-keyword">in</span> initializer)
<span class="hljs-keyword">new</span> Block expressions</pre></div></div>
</li>
<li id="section-155">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-155">&#182;</a>
</div>
<p>Add an expression to the class initializer</p>
<p>This is the key method for determining whether an expression in a class
body should appear in the initializer or the executable body. If the given
<code>node</code> is valid in a class body the method will return a (new, modified,
or identical) node for inclusion in the class initializer, otherwise
nothing will be returned and the node will appear in the executable body.</p>
<p>At time of writing, only methods (instance and static) are valid in ES
class initializers. As new ES class features (such as class fields) reach
Stage 4, this method will need to be updated to support them. We
additionally allow <code>PassthroughLiteral</code>s (backticked expressions) in the
initializer as an escape hatch for ES features that are not implemented
(e.g. getters and setters defined via the <code>get</code> and <code>set</code> keywords as
opposed to the <code>Object.defineProperty</code> method).</p>
</div>
<div class="content"><div class='highlight'><pre> addInitializerExpression: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">if</span> node.unwrapAll() <span class="hljs-keyword">instanceof</span> PassthroughLiteral
node
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @validInitializerMethod node
@addInitializerMethod node
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-156">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-156">&#182;</a>
</div>
<p>Checks if the given node is a valid ES class initializer method.</p>
</div>
<div class="content"><div class='highlight'><pre> validInitializerMethod: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> node.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> node.variable.hasProperties()
<span class="hljs-keyword">return</span> node.variable.looksStatic(@name) <span class="hljs-keyword">and</span> (@name <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.value.bound)</pre></div></div>
</li>
<li id="section-157">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-157">&#182;</a>
</div>
<p>Returns a configured class initializer method</p>
</div>
<div class="content"><div class='highlight'><pre> addInitializerMethod: <span class="hljs-function"><span class="hljs-params">(assign)</span> -&gt;</span>
{ variable, value: method } = assign
method.isMethod = <span class="hljs-literal">yes</span>
method.isStatic = variable.looksStatic @name
<span class="hljs-keyword">if</span> method.isStatic
method.name = variable.properties[<span class="hljs-number">0</span>]
<span class="hljs-keyword">else</span>
methodName = variable.base
method.name = <span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> methodName.shouldCache() <span class="hljs-keyword">then</span> Index <span class="hljs-keyword">else</span> Access) methodName
method.name.updateLocationDataIfMissing methodName.locationData
method.ctor = (<span class="hljs-keyword">if</span> @parent <span class="hljs-keyword">then</span> <span class="hljs-string">'derived'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'base'</span>) <span class="hljs-keyword">if</span> methodName.value <span class="hljs-keyword">is</span> <span class="hljs-string">'constructor'</span>
method.error <span class="hljs-string">'Cannot define a constructor as a bound (fat arrow) function'</span> <span class="hljs-keyword">if</span> method.bound <span class="hljs-keyword">and</span> method.ctor
method
makeDefaultConstructor: <span class="hljs-function">-&gt;</span>
ctor = @addInitializerMethod <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'constructor'</span>), <span class="hljs-keyword">new</span> Code
@body.unshift ctor
<span class="hljs-keyword">if</span> @parent
ctor.body.push <span class="hljs-keyword">new</span> SuperCall <span class="hljs-keyword">new</span> Super, [<span class="hljs-keyword">new</span> Splat <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span>]
<span class="hljs-keyword">if</span> @externalCtor
applyCtor = <span class="hljs-keyword">new</span> Value @externalCtor, [ <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'apply'</span> ]
applyArgs = [ <span class="hljs-keyword">new</span> ThisLiteral, <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span> ]
ctor.body.push <span class="hljs-keyword">new</span> Call applyCtor, applyArgs
ctor.body.makeReturn()
ctor
proxyBoundMethods: <span class="hljs-function">-&gt;</span>
@ctor.thisAssignments = <span class="hljs-keyword">for</span> method <span class="hljs-keyword">in</span> @boundMethods
method.classVariable = @variableRef <span class="hljs-keyword">if</span> @parent
name = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> ThisLiteral, [ method.name ])
<span class="hljs-keyword">new</span> Assign name, <span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(name, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'bind'</span>]), [<span class="hljs-keyword">new</span> ThisLiteral])
<span class="hljs-literal">null</span>
exports.ExecutableClassBody = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExecutableClassBody</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
children: [ <span class="hljs-string">'class'</span>, <span class="hljs-string">'body'</span> ]
defaultClassVariableName: <span class="hljs-string">'_Class'</span>
constructor: <span class="hljs-function"><span class="hljs-params">(@class, @body = <span class="hljs-keyword">new</span> Block)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> jumpNode = @body.jumps()
jumpNode.error <span class="hljs-string">'Class bodies cannot contain pure statements'</span>
<span class="hljs-keyword">if</span> argumentsNode = @body.contains isLiteralArguments
argumentsNode.error <span class="hljs-string">"Class bodies shouldn't reference arguments"</span>
params = []
args = [<span class="hljs-keyword">new</span> ThisLiteral]
wrapper = <span class="hljs-keyword">new</span> Code params, @body
klass = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Call (<span class="hljs-keyword">new</span> Value wrapper, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'call'</span>]), args
@body.spaced = <span class="hljs-literal">true</span>
o.classScope = wrapper.makeScope o.scope
@name = @class.name ? o.classScope.freeVariable @defaultClassVariableName
ident = <span class="hljs-keyword">new</span> IdentifierLiteral @name
directives = @walkBody()
@setContext()
<span class="hljs-keyword">if</span> @class.hasNameClash
parent = <span class="hljs-keyword">new</span> IdentifierLiteral o.classScope.freeVariable <span class="hljs-string">'superClass'</span>
wrapper.params.push <span class="hljs-keyword">new</span> Param parent
args.push @class.parent
@class.parent = parent
<span class="hljs-keyword">if</span> @externalCtor
externalCtor = <span class="hljs-keyword">new</span> IdentifierLiteral o.classScope.freeVariable <span class="hljs-string">'ctor'</span>, reserve: <span class="hljs-literal">no</span>
@class.externalCtor = externalCtor
@externalCtor.variable.base = externalCtor
<span class="hljs-keyword">if</span> @name <span class="hljs-keyword">isnt</span> @class.name
@body.expressions.unshift <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> IdentifierLiteral @name), @class
<span class="hljs-keyword">else</span>
@body.expressions.unshift @class
@body.expressions.unshift directives...
@body.push ident
klass.compileToFragments o</pre></div></div>
</li>
<li id="section-158">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-158">&#182;</a>
</div>
<p>Traverse the classs children and:</p>
<ul>
<li>Hoist valid ES properties into <code>@properties</code></li>
<li>Hoist static assignments into <code>@properties</code></li>
<li>Convert invalid ES properties into class or prototype assignments</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> walkBody: <span class="hljs-function">-&gt;</span>
directives = []
index = <span class="hljs-number">0</span>
<span class="hljs-keyword">while</span> expr = @body.expressions[index]
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isString()
<span class="hljs-keyword">if</span> expr.hoisted
index++
<span class="hljs-keyword">else</span>
directives.push @body.expressions.splice(index, <span class="hljs-number">1</span>)...
@traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">or</span> child <span class="hljs-keyword">instanceof</span> HoistTarget
cont = <span class="hljs-literal">true</span>
<span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> Block
<span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> child.expressions
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> node.isObject(<span class="hljs-literal">true</span>)
cont = <span class="hljs-literal">false</span>
child.expressions[i] = @addProperties node.base.properties
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> node.variable.looksStatic @name
node.value.isStatic = <span class="hljs-literal">yes</span>
child.expressions = flatten child.expressions
cont
directives
setContext: <span class="hljs-function">-&gt;</span>
@body.traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> ThisLiteral
node.value = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound <span class="hljs-keyword">and</span> node.isStatic
node.context = @name</pre></div></div>
</li>
<li id="section-159">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-159">&#182;</a>
</div>
<p>Make class/prototype assignments for invalid ES properties</p>
</div>
<div class="content"><div class='highlight'><pre> addProperties: <span class="hljs-function"><span class="hljs-params">(assigns)</span> -&gt;</span>
result = <span class="hljs-keyword">for</span> assign <span class="hljs-keyword">in</span> assigns
variable = assign.variable
base = variable?.base
value = assign.value
<span class="hljs-keyword">delete</span> assign.context
<span class="hljs-keyword">if</span> base.value <span class="hljs-keyword">is</span> <span class="hljs-string">'constructor'</span>
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">instanceof</span> Code
base.error <span class="hljs-string">'constructors must be defined at the top level of a class body'</span></pre></div></div>
</li>
<li id="section-160">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-160">&#182;</a>
</div>
<p>The class scope is not available yet, so return the assignment to update later</p>
</div>
<div class="content"><div class='highlight'><pre> assign = @externalCtor = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value, value
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> assign.variable.<span class="hljs-keyword">this</span>
name = <span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> base.shouldCache() <span class="hljs-keyword">then</span> Index <span class="hljs-keyword">else</span> Access) base
prototype = <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'prototype'</span>
variable = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> ThisLiteral(), [ prototype, name ]
assign.variable = variable
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> assign.value <span class="hljs-keyword">instanceof</span> Code
assign.value.isStatic = <span class="hljs-literal">true</span>
assign
compact result</pre></div></div>
</li>
<li id="section-161">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-161">&#182;</a>
</div>
<h3 id="import-and-export">Import and Export</h3>
</div>
<div class="content"><div class='highlight'><pre>
exports.ModuleDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@clause, @source)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@checkSource()
children: [<span class="hljs-string">'clause'</span>, <span class="hljs-string">'source'</span>]
isStatement: YES
jumps: THIS
makeReturn: THIS
checkSource: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @source? <span class="hljs-keyword">and</span> @source <span class="hljs-keyword">instanceof</span> StringWithInterpolations
@source.error <span class="hljs-string">'the name of the module to be imported from must be an uninterpolated string'</span>
checkScope: <span class="hljs-function"><span class="hljs-params">(o, moduleDeclarationType)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.indent.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
@error <span class="hljs-string">"<span class="hljs-subst">#{moduleDeclarationType}</span> statements must be at top-level scope"</span>
exports.ImportDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleDeclaration</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o, <span class="hljs-string">'import'</span>
o.importedSymbols = []
code = []
code.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>import "</span>
code.push @clause.compileNode(o)... <span class="hljs-keyword">if</span> @clause?
<span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">' from '</span> <span class="hljs-keyword">unless</span> @clause <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>
code.push @makeCode @source.value
code.push @makeCode <span class="hljs-string">';'</span>
code
exports.ImportClause = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportClause</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@defaultBinding, @namedImports)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'defaultBinding'</span>, <span class="hljs-string">'namedImports'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = []
<span class="hljs-keyword">if</span> @defaultBinding?
code.push @defaultBinding.compileNode(o)...
code.push @makeCode <span class="hljs-string">', '</span> <span class="hljs-keyword">if</span> @namedImports?
<span class="hljs-keyword">if</span> @namedImports?
code.push @namedImports.compileNode(o)...
code
exports.ExportDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleDeclaration</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o, <span class="hljs-string">'export'</span>
code = []
code.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>export "</span>
code.push @makeCode <span class="hljs-string">'default '</span> <span class="hljs-keyword">if</span> @ <span class="hljs-keyword">instanceof</span> ExportDefaultDeclaration
<span class="hljs-keyword">if</span> @ <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> ExportDefaultDeclaration <span class="hljs-keyword">and</span>
(@clause <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">or</span> @clause <span class="hljs-keyword">instanceof</span> Class)</pre></div></div>
</li>
<li id="section-162">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-162">&#182;</a>
</div>
<p>Prevent exporting an anonymous class; all exported members must be named</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @clause <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @clause.variable
@clause.error <span class="hljs-string">'anonymous classes cannot be exported'</span>
code.push @makeCode <span class="hljs-string">'var '</span>
@clause.moduleDeclaration = <span class="hljs-string">'export'</span>
<span class="hljs-keyword">if</span> @clause.body? <span class="hljs-keyword">and</span> @clause.body <span class="hljs-keyword">instanceof</span> Block
code = code.concat @clause.compileToFragments o, LEVEL_TOP
<span class="hljs-keyword">else</span>
code = code.concat @clause.compileNode o
code.push @makeCode <span class="hljs-string">" from <span class="hljs-subst">#{@source.value}</span>"</span> <span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">';'</span>
code
exports.ExportNamedDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportNamedDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ExportDefaultDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportDefaultDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ExportAllDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportAllDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ModuleSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@specifiers)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'specifiers'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = []
o.indent += TAB
compiledList = (specifier.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> specifier <span class="hljs-keyword">in</span> @specifiers)
<span class="hljs-keyword">if</span> @specifiers.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
code.push @makeCode <span class="hljs-string">"{\n<span class="hljs-subst">#{o.indent}</span>"</span>
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledList
code.push @makeCode(<span class="hljs-string">",\n<span class="hljs-subst">#{o.indent}</span>"</span>) <span class="hljs-keyword">if</span> index
code.push fragments...
code.push @makeCode <span class="hljs-string">"\n}"</span>
<span class="hljs-keyword">else</span>
code.push @makeCode <span class="hljs-string">'{}'</span>
code
exports.ImportSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifierList</span></span>
exports.ExportSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifierList</span></span>
exports.ModuleSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@original, @alias, @moduleDeclarationType)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
<span class="hljs-keyword">if</span> @original.comments <span class="hljs-keyword">or</span> @alias?.comments
@comments = []
@comments.push @original.comments... <span class="hljs-keyword">if</span> @original.comments
@comments.push @alias.comments... <span class="hljs-keyword">if</span> @alias?.comments</pre></div></div>
</li>
<li id="section-163">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-163">&#182;</a>
</div>
<p>The name of the variable entering the local scope</p>
</div>
<div class="content"><div class='highlight'><pre> @identifier = <span class="hljs-keyword">if</span> @alias? <span class="hljs-keyword">then</span> @alias.value <span class="hljs-keyword">else</span> @original.value
children: [<span class="hljs-string">'original'</span>, <span class="hljs-string">'alias'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.scope.find @identifier, @moduleDeclarationType
code = []
code.push @makeCode @original.value
code.push @makeCode <span class="hljs-string">" as <span class="hljs-subst">#{@alias.value}</span>"</span> <span class="hljs-keyword">if</span> @alias?
code
exports.ImportSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifier</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(imported, local)</span> -&gt;</span>
<span class="hljs-keyword">super</span> imported, local, <span class="hljs-string">'import'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-164">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-164">&#182;</a>
</div>
<p>Per the spec, symbols cant be imported multiple times
(e.g. <code>import { foo, foo } from &#39;lib&#39;</code> is invalid)</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @identifier <span class="hljs-keyword">in</span> o.importedSymbols <span class="hljs-keyword">or</span> o.scope.check(@identifier)
@error <span class="hljs-string">"'<span class="hljs-subst">#{@identifier}</span>' has already been declared"</span>
<span class="hljs-keyword">else</span>
o.importedSymbols.push @identifier
<span class="hljs-keyword">super</span> o
exports.ImportDefaultSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportDefaultSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ImportSpecifier</span></span>
exports.ImportNamespaceSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportNamespaceSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ImportSpecifier</span></span>
exports.ExportSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifier</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(local, exported)</span> -&gt;</span>
<span class="hljs-keyword">super</span> local, exported, <span class="hljs-string">'export'</span></pre></div></div>
</li>
<li id="section-165">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-165">&#182;</a>
</div>
<h3 id="assign">Assign</h3>
</div>
</li>
<li id="section-166">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-166">&#182;</a>
</div>
<p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the
property of an object including within object literals.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Assign = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Assign</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @value, @context, options = {})</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
{@param, @subpattern, @operatorToken, @moduleDeclaration} = options
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'value'</span>]
isAssignable: YES
isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">and</span> @context? <span class="hljs-keyword">and</span> (@moduleDeclaration <span class="hljs-keyword">or</span> <span class="hljs-string">"?"</span> <span class="hljs-keyword">in</span> @context)
checkAssignability: <span class="hljs-function"><span class="hljs-params">(o, varBase)</span> -&gt;</span>
<span class="hljs-keyword">if</span> Object::hasOwnProperty.call(o.scope.positions, varBase.value) <span class="hljs-keyword">and</span>
o.scope.variables[o.scope.positions[varBase.value]].type <span class="hljs-keyword">is</span> <span class="hljs-string">'import'</span>
varBase.error <span class="hljs-string">"'<span class="hljs-subst">#{varBase.value}</span>' is read-only"</span>
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@[<span class="hljs-keyword">if</span> @context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'value'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'variable'</span>].assigns name
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'variable'</span></pre></div></div>
</li>
<li id="section-167">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-167">&#182;</a>
</div>
<p>Compile an assignment, delegating to <code>compileDestructuring</code> or
<code>compileSplice</code> if appropriate. Keep track of the name of the base object
weve been assigned to, for correct internal references. If the variable
has not been seen yet within the current scope, declare it.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
isValue = @variable <span class="hljs-keyword">instanceof</span> Value
<span class="hljs-keyword">if</span> isValue</pre></div></div>
</li>
<li id="section-168">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-168">&#182;</a>
</div>
<p>When compiling <code>@variable</code>, remember if it is part of a function parameter.</p>
</div>
<div class="content"><div class='highlight'><pre> @variable.param = @param</pre></div></div>
</li>
<li id="section-169">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-169">&#182;</a>
</div>
<p>If <code>@variable</code> is an array or an object, were destructuring;
if its also <code>isAssignable()</code>, the destructuring syntax is supported
in ES and we can output it as is; otherwise we <code>@compileDestructuring</code>
and convert this ES-unsupported destructuring into acceptable output.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @variable.isArray() <span class="hljs-keyword">or</span> @variable.isObject()</pre></div></div>
</li>
<li id="section-170">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-170">&#182;</a>
</div>
<p>This is the left-hand side of an assignment; let <code>Arr</code> and <code>Obj</code>
know that, so that those nodes know that theyre assignable as
destructured variables.</p>
</div>
<div class="content"><div class='highlight'><pre> @variable.base.lhs = <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-171">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-171">&#182;</a>
</div>
<p>Check if @variable contains Obj with splats.</p>
</div>
<div class="content"><div class='highlight'><pre> hasSplat = @variable.contains (node) -&gt; node <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> node.hasSplat()
<span class="hljs-keyword">return</span> @compileDestructuring o <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @variable.isAssignable() <span class="hljs-keyword">or</span> @variable.isArray() <span class="hljs-keyword">and</span> hasSplat</pre></div></div>
</li>
<li id="section-172">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-172">&#182;</a>
</div>
<p>Object destructuring. Can be removed once ES proposal hits Stage 4.</p>
</div>
<div class="content"><div class='highlight'><pre> objDestructAnswer = @compileObjectDestruct(o) <span class="hljs-keyword">if</span> @variable.isObject() <span class="hljs-keyword">and</span> hasSplat
<span class="hljs-keyword">return</span> objDestructAnswer <span class="hljs-keyword">if</span> objDestructAnswer
<span class="hljs-keyword">return</span> @compileSplice o <span class="hljs-keyword">if</span> @variable.isSplice()
<span class="hljs-keyword">return</span> @compileConditional o <span class="hljs-keyword">if</span> @context <span class="hljs-keyword">in</span> [<span class="hljs-string">'||='</span>, <span class="hljs-string">'&amp;&amp;='</span>, <span class="hljs-string">'?='</span>]
<span class="hljs-keyword">return</span> @compileSpecialMath o <span class="hljs-keyword">if</span> @context <span class="hljs-keyword">in</span> [<span class="hljs-string">'**='</span>, <span class="hljs-string">'//='</span>, <span class="hljs-string">'%%='</span>]
<span class="hljs-keyword">unless</span> @context
varBase = @variable.unwrapAll()
<span class="hljs-keyword">unless</span> varBase.isAssignable()
@variable.error <span class="hljs-string">"'<span class="hljs-subst">#{@variable.compile o}</span>' can't be assigned"</span>
varBase.eachName (name) =&gt;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> name.hasProperties?()
message = isUnassignable name.value
name.error message <span class="hljs-keyword">if</span> message</pre></div></div>
</li>
<li id="section-173">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-173">&#182;</a>
</div>
<p><code>moduleDeclaration</code> can be <code>&#39;import&#39;</code> or <code>&#39;export&#39;</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> @checkAssignability o, name
<span class="hljs-keyword">if</span> @moduleDeclaration
o.scope.add name.value, @moduleDeclaration
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @param
o.scope.add name.value,
<span class="hljs-keyword">if</span> @param <span class="hljs-keyword">is</span> <span class="hljs-string">'alwaysDeclare'</span>
<span class="hljs-string">'var'</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">'param'</span>
<span class="hljs-keyword">else</span>
o.scope.find name.value</pre></div></div>
</li>
<li id="section-174">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-174">&#182;</a>
</div>
<p>If this assignment identifier has one or more herecomments
attached, output them as part of the declarations line (unless
other herecomments are already staged there) for compatibility
with Flow typing. Dont do this if this assignment is for a
class, e.g. <code>ClassName = class ClassName {</code>, as Flow requires
the comment to be between the class name and the <code>{</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> name.comments <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.comments[name.value] <span class="hljs-keyword">and</span>
@value <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">and</span>
name.comments.every(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.multiline)
commentsNode = <span class="hljs-keyword">new</span> IdentifierLiteral name.value
commentsNode.comments = name.comments
commentFragments = []
@compileCommentFragments o, commentsNode, commentFragments
o.scope.comments[name.value] = commentFragments
<span class="hljs-keyword">if</span> @value <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">if</span> @value.isStatic
@value.name = @variable.properties[<span class="hljs-number">0</span>]
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @variable.properties?.length &gt;= <span class="hljs-number">2</span>
[properties..., prototype, name] = @variable.properties
@value.name = name <span class="hljs-keyword">if</span> prototype.name?.value <span class="hljs-keyword">is</span> <span class="hljs-string">'prototype'</span>
@value.base.csxAttribute = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @csx
val = @value.compileToFragments o, LEVEL_LIST
compiledName = @variable.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">if</span> @context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> @variable.shouldCache()
compiledName.unshift @makeCode <span class="hljs-string">'['</span>
compiledName.push @makeCode <span class="hljs-string">']'</span>
<span class="hljs-keyword">return</span> compiledName.concat @makeCode(<span class="hljs-keyword">if</span> @csx <span class="hljs-keyword">then</span> <span class="hljs-string">'='</span> <span class="hljs-keyword">else</span> <span class="hljs-string">': '</span>), val
answer = compiledName.concat @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{ @context <span class="hljs-keyword">or</span> <span class="hljs-string">'='</span> }</span> "</span>), val</pre></div></div>
</li>
<li id="section-175">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-175">&#182;</a>
</div>
<p>Per <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration</a>,
if were destructuring without declaring, the destructuring assignment must be wrapped in parentheses.
The assignment is wrapped in parentheses if o.level has lower precedence than LEVEL_LIST (3)
(i.e. LEVEL_COND (4), LEVEL_OP (5) or LEVEL_ACCESS (6)), or if were destructuring object, e.g. {a,b} = obj.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> o.level &gt; LEVEL_LIST <span class="hljs-keyword">or</span> isValue <span class="hljs-keyword">and</span> @variable.base <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @nestedLhs <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@param <span class="hljs-keyword">is</span> <span class="hljs-literal">yes</span>)
@wrapInParentheses answer
<span class="hljs-keyword">else</span>
answer</pre></div></div>
</li>
<li id="section-176">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-176">&#182;</a>
</div>
<p>Check object destructuring variable for rest elements;
can be removed once ES proposal hits Stage 4.</p>
</div>
<div class="content"><div class='highlight'><pre> compileObjectDestruct: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-177">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-177">&#182;</a>
</div>
<p>Returns a safe (cached) reference to the key for a given property</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">getPropKey</span> = <span class="hljs-params">(prop)</span> -&gt;</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign
[prop.variable, key] = prop.variable.cache o
key
<span class="hljs-keyword">else</span>
prop</pre></div></div>
</li>
<li id="section-178">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-178">&#182;</a>
</div>
<p>Returns the name of a given property for use with excludeProps
Property names are quoted (e.g. <code>a: b</code> -&gt; a), and everything else uses the key reference
(e.g. <code>&#39;a&#39;: b -&gt; &#39;a&#39;</code>, <code>&quot;#{a}&quot;: b</code> -&gt; <cached>`)</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">getPropName</span> = <span class="hljs-params">(prop)</span> -&gt;</span>
key = getPropKey prop
cached = prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.variable <span class="hljs-keyword">isnt</span> key
<span class="hljs-keyword">if</span> cached <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> key.isAssignable()
key
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Literal <span class="hljs-string">"'<span class="hljs-subst">#{key.compileWithoutComments o}</span>'"</span></pre></div></div>
</li>
<li id="section-179">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-179">&#182;</a>
</div>
<p>Recursive function for searching and storing rest elements in objects.
e.g. <code>{[properties...]} = source</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">traverseRest</span> = <span class="hljs-params">(properties, source)</span> =&gt;</span>
restElements = []
restIndex = <span class="hljs-literal">undefined</span>
source = <span class="hljs-keyword">new</span> Value source <span class="hljs-keyword">unless</span> source.properties?
<span class="hljs-keyword">for</span> prop, index <span class="hljs-keyword">in</span> properties
nestedSourceDefault = nestedSource = nestedProperties = <span class="hljs-literal">null</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign</pre></div></div>
</li>
<li id="section-180">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-180">&#182;</a>
</div>
<p>prop is <code>k: expr</code>, we need to check <code>expr</code> for nested splats</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> prop.value.isObject?()</pre></div></div>
</li>
<li id="section-181">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-181">&#182;</a>
</div>
<p>prop is <code>k = {...}</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>
</li>
<li id="section-182">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-182">&#182;</a>
</div>
<p>prop is <code>k: {...}</code></p>
</div>
<div class="content"><div class='highlight'><pre> nestedProperties = prop.value.base.properties
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop.value <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.value.variable.isObject()</pre></div></div>
</li>
<li id="section-183">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-183">&#182;</a>
</div>
<p>prop is <code>k: {...} = default</code></p>
</div>
<div class="content"><div class='highlight'><pre> nestedProperties = prop.value.variable.base.properties
[prop.value.value, nestedSourceDefault] = prop.value.value.cache o
<span class="hljs-keyword">if</span> nestedProperties
nestedSource = <span class="hljs-keyword">new</span> Value source.base, source.properties.concat [<span class="hljs-keyword">new</span> Access getPropKey prop]
nestedSource = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, nestedSource, nestedSourceDefault <span class="hljs-keyword">if</span> nestedSourceDefault
restElements.push traverseRest(nestedProperties, nestedSource)...
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Splat
prop.error <span class="hljs-string">"multiple rest elements are disallowed in object destructuring"</span> <span class="hljs-keyword">if</span> restIndex?
restIndex = index
restElements.push {
name: prop.name.unwrapAll()
source
excludeProps: <span class="hljs-keyword">new</span> Arr (getPropName p <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> properties <span class="hljs-keyword">when</span> p <span class="hljs-keyword">isnt</span> prop)
}
<span class="hljs-keyword">if</span> restIndex?</pre></div></div>
</li>
<li id="section-184">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-184">&#182;</a>
</div>
<p>Remove rest element from the properties after iteration</p>
</div>
<div class="content"><div class='highlight'><pre> properties.splice restIndex, <span class="hljs-number">1</span>
restElements</pre></div></div>
</li>
<li id="section-185">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-185">&#182;</a>
</div>
<p>Cache the value for reuse with rest elements.</p>
</div>
<div class="content"><div class='highlight'><pre> valueRefTemp =
<span class="hljs-keyword">if</span> @value.shouldCache()
<span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>, reserve: <span class="hljs-literal">false</span>
<span class="hljs-keyword">else</span>
@value.base</pre></div></div>
</li>
<li id="section-186">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-186">&#182;</a>
</div>
<p>Find all rest elements.</p>
</div>
<div class="content"><div class='highlight'><pre> restElements = traverseRest @variable.base.properties, valueRefTemp
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> restElements <span class="hljs-keyword">and</span> restElements.length &gt; <span class="hljs-number">0</span>
[@value, valueRef] = @value.cache o
result = <span class="hljs-keyword">new</span> Block [@]
<span class="hljs-keyword">for</span> restElement <span class="hljs-keyword">in</span> restElements
value = <span class="hljs-keyword">new</span> Call <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'objectWithoutKeys'</span>, o), [restElement.source, restElement.excludeProps]
result.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(restElement.name), value, <span class="hljs-literal">null</span>, param: <span class="hljs-keyword">if</span> @param <span class="hljs-keyword">then</span> <span class="hljs-string">'alwaysDeclare'</span> <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>
fragments = result.compileToFragments o
<span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP</pre></div></div>
</li>
<li id="section-187">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-187">&#182;</a>
</div>
<p>Remove leading tab and trailing semicolon</p>
</div>
<div class="content"><div class='highlight'><pre> fragments.shift()
fragments.pop()
fragments</pre></div></div>
</li>
<li id="section-188">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-188">&#182;</a>
</div>
<p>Brief implementation of recursive pattern matching, when assigning array or
object literals to a value. Peeks at their properties to assign inner names.</p>
</div>
<div class="content"><div class='highlight'><pre> compileDestructuring: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP
{value} = <span class="hljs-keyword">this</span>
{objects} = @variable.base
olen = objects.length</pre></div></div>
</li>
<li id="section-189">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-189">&#182;</a>
</div>
<p>Special-case for <code>{} = a</code> and <code>[] = a</code> (empty patterns).
Compile to simply <code>a</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
code = value.compileToFragments o
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_OP <span class="hljs-keyword">then</span> @wrapInParentheses code <span class="hljs-keyword">else</span> code
[obj] = objects</pre></div></div>
</li>
<li id="section-190">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-190">&#182;</a>
</div>
<p>Disallow <code>[...] = a</code> for some reason. (Could be equivalent to <code>[] = a</code>?)</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">'Destructuring assignment has no target'</span></pre></div></div>
</li>
<li id="section-191">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-191">&#182;</a>
</div>
<p>Count all <code>Splats</code>: [a, b, c…, d, e]</p>
</div>
<div class="content"><div class='highlight'><pre> splats = (i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat)</pre></div></div>
</li>
<li id="section-192">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-192">&#182;</a>
</div>
<p>Count all <code>Expansions</code>: [a, b, …, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre> expans = (i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Expansion)</pre></div></div>
</li>
<li id="section-193">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-193">&#182;</a>
</div>
<p>Combine splats and expansions.</p>
</div>
<div class="content"><div class='highlight'><pre> splatsAndExpans = [splats..., expans...]</pre></div></div>
</li>
<li id="section-194">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-194">&#182;</a>
</div>
<p>Show error if there is more than one <code>Splat</code>, or <code>Expansion</code>.
Examples: [a, b, c…, d, e, f…], [a, b, …, c, d, …], [a, b, …, c, d, e…]</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> splatsAndExpans.length &gt; <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-195">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-195">&#182;</a>
</div>
<p>Sort splatsAndExpans so we can show error at first disallowed token.</p>
</div>
<div class="content"><div class='highlight'><pre> objects[splatsAndExpans.sort()[<span class="hljs-number">1</span>]].error <span class="hljs-string">"multiple splats/expansions are disallowed in an assignment"</span>
isSplat = splats?.length &gt; <span class="hljs-number">0</span>
isExpans = expans?.length &gt; <span class="hljs-number">0</span>
isObject = @variable.isObject()
isArray = @variable.isArray()
vvar = value.compileToFragments o, LEVEL_LIST
vvarText = fragmentsToText vvar
assigns = []</pre></div></div>
</li>
<li id="section-196">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-196">&#182;</a>
</div>
<p>At this point, there are several things to destructure. So the <code>fn()</code> in
<code>{a, b} = fn()</code> must be cached, for example. Make vvar into a simple
variable if it isnt already.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> value.unwrap() <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">or</span> @variable.assigns(vvarText)
ref = o.scope.freeVariable <span class="hljs-string">'ref'</span>
assigns.push [@makeCode(ref + <span class="hljs-string">' = '</span>), vvar...]
vvar = [@makeCode ref]
vvarText = ref
<span class="hljs-function">
<span class="hljs-title">slicer</span> = <span class="hljs-params">(type)</span> -&gt;</span> (vvar, start, end = <span class="hljs-literal">no</span>) -&gt;
vvar = <span class="hljs-keyword">new</span> IdentifierLiteral vvar <span class="hljs-keyword">unless</span> vvar <span class="hljs-keyword">instanceof</span> Value
args = [vvar, <span class="hljs-keyword">new</span> NumberLiteral(start)]
args.push <span class="hljs-keyword">new</span> NumberLiteral end <span class="hljs-keyword">if</span> end
slice = <span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> IdentifierLiteral utility type, o), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'call'</span>]
<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Call slice, args</pre></div></div>
</li>
<li id="section-197">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-197">&#182;</a>
</div>
<p>Helper which outputs <code>[].slice</code> code.</p>
</div>
<div class="content"><div class='highlight'><pre> compSlice = slicer <span class="hljs-string">"slice"</span></pre></div></div>
</li>
<li id="section-198">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-198">&#182;</a>
</div>
<p>Helper which outputs <code>[].splice</code> code.</p>
</div>
<div class="content"><div class='highlight'><pre> compSplice = slicer <span class="hljs-string">"splice"</span></pre></div></div>
</li>
<li id="section-199">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-199">&#182;</a>
</div>
<p>Check if <code>objects</code> array contains object spread (<code>{a, r...}</code>), e.g. <code>[a, b, {c, r...}]</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">hasObjSpreads</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
(i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs <span class="hljs-keyword">when</span> obj.base <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> obj.base.hasSplat())</pre></div></div>
</li>
<li id="section-200">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-200">&#182;</a>
</div>
<p>Check if <code>objects</code> array contains any instance of <code>Assign</code>, e.g. {a:1}.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">hasObjAssigns</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
(i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>)</pre></div></div>
</li>
<li id="section-201">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-201">&#182;</a>
</div>
<p>Check if <code>objects</code> array contains any unassignable object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">objIsUnassignable</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> objs <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> obj.isAssignable()
<span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-202">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-202">&#182;</a>
</div>
<p><code>objects</code> are complex when there is object spread ({a…}), object assign ({a:1}),
unassignable object, or just a single node.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">complexObjects</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
hasObjSpreads(objs).length <span class="hljs-keyword">or</span> hasObjAssigns(objs).length <span class="hljs-keyword">or</span> objIsUnassignable(objs) <span class="hljs-keyword">or</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-203">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-203">&#182;</a>
</div>
<p>“Complex” <code>objects</code> are processed in a loop.
Examples: [a, b, {c, r…}, d], [a, …, {b, r…}, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">loopObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
objSpreads = hasObjSpreads objs
<span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs</pre></div></div>
</li>
<li id="section-204">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-204">&#182;</a>
</div>
<p><code>Elision</code> can be skipped.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Elision</pre></div></div>
</li>
<li id="section-205">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-205">&#182;</a>
</div>
<p>If <code>obj</code> is {a: 1}</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
{variable: {base: idx}, value: vvar} = obj
{variable: vvar} = vvar <span class="hljs-keyword">if</span> vvar <span class="hljs-keyword">instanceof</span> Assign
idx =
<span class="hljs-keyword">if</span> vvar.<span class="hljs-keyword">this</span>
vvar.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName vvar.unwrap().value
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
vval = <span class="hljs-keyword">new</span> Value value, [<span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> acc <span class="hljs-keyword">then</span> Access <span class="hljs-keyword">else</span> Index) idx]
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-206">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-206">&#182;</a>
</div>
<p><code>obj</code> is [a…], {a…} or a</p>
</div>
<div class="content"><div class='highlight'><pre> vvar = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Value obj.name
<span class="hljs-keyword">when</span> i <span class="hljs-keyword">in</span> objSpreads <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Value obj.base
<span class="hljs-keyword">else</span> obj
vval = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">then</span> compSlice(vvarTxt, i)
<span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarTxt), [<span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> NumberLiteral i]
message = isUnassignable vvar.unwrap().value
vvar.error message <span class="hljs-keyword">if</span> message
assigns.push <span class="hljs-keyword">new</span> Assign(vvar, vval, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST</pre></div></div>
</li>
<li id="section-207">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-207">&#182;</a>
</div>
<p>“Simple” <code>objects</code> can be split and compiled to arrays, [a, b, c] = arr, [a, b, c…] = arr</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">assignObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
vvar = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Arr(objs, <span class="hljs-literal">yes</span>)
vval = <span class="hljs-keyword">if</span> vvarTxt <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">then</span> vvarTxt <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarTxt)
assigns.push <span class="hljs-keyword">new</span> Assign(vvar, vval, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST
<span class="hljs-function">
<span class="hljs-title">processObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> -&gt;</span>
<span class="hljs-keyword">if</span> complexObjects objs
loopObjects objs, vvar, vvarTxt
<span class="hljs-keyword">else</span>
assignObjects objs, vvar, vvarTxt</pre></div></div>
</li>
<li id="section-208">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-208">&#182;</a>
</div>
<p>In case there is <code>Splat</code> or <code>Expansion</code> in <code>objects</code>,
we can split array in two simple subarrays.
<code>Splat</code> [a, b, c…, d, e] can be split into [a, b, c…] and [d, e].
<code>Expansion</code> [a, b, …, c, d] can be split into [a, b] and [c, d].
Examples:
a) <code>Splat</code>
CS: [a, b, c…, d, e] = arr
JS: [a, b, …c] = arr, [d, e] = splice.call(c, -2)
b) <code>Expansion</code>
CS: [a, b, …, d, e] = arr
JS: [a, b] = arr, [d, e] = slice.call(arr, -2)</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> splatsAndExpans.length
expIdx = splatsAndExpans[<span class="hljs-number">0</span>]
leftObjs = objects.slice <span class="hljs-number">0</span>, expIdx + (<span class="hljs-keyword">if</span> isSplat <span class="hljs-keyword">then</span> <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-number">0</span>)
rightObjs = objects.slice expIdx + <span class="hljs-number">1</span>
processObjects leftObjs, vvar, vvarText <span class="hljs-keyword">if</span> leftObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> rightObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span></pre></div></div>
</li>
<li id="section-209">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-209">&#182;</a>
</div>
<p>Slice or splice <code>objects</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> refExp = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> isSplat <span class="hljs-keyword">then</span> compSplice <span class="hljs-keyword">new</span> Value(objects[expIdx].name), rightObjs.length * <span class="hljs-number">-1</span>
<span class="hljs-keyword">when</span> isExpans <span class="hljs-keyword">then</span> compSlice vvarText, rightObjs.length * <span class="hljs-number">-1</span>
<span class="hljs-keyword">if</span> complexObjects rightObjs
restVar = refExp
refExp = o.scope.freeVariable <span class="hljs-string">'ref'</span>
assigns.push [@makeCode(refExp + <span class="hljs-string">' = '</span>), restVar.compileToFragments(o, LEVEL_LIST)...]
processObjects rightObjs, vvar, refExp
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-210">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-210">&#182;</a>
</div>
<p>There is no <code>Splat</code> or <code>Expansion</code> in <code>objects</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> processObjects objects, vvar, vvarText
assigns.push vvar <span class="hljs-keyword">unless</span> top <span class="hljs-keyword">or</span> @subpattern
fragments = @joinFragmentArrays assigns, <span class="hljs-string">', '</span>
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments</pre></div></div>
</li>
<li id="section-211">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-211">&#182;</a>
</div>
<p>When compiling a conditional assignment, take care to ensure that the
operands are only evaluated once, even though we have to reference them
more than once.</p>
</div>
<div class="content"><div class='highlight'><pre> compileConditional: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[left, right] = @variable.cacheReference o</pre></div></div>
</li>
<li id="section-212">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-212">&#182;</a>
</div>
<p>Disallow conditional assignment of undefined variables.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> left.properties.length <span class="hljs-keyword">and</span> left.base <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span>
left.base <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check left.base.value
@variable.error <span class="hljs-string">"the variable \"<span class="hljs-subst">#{left.base.value}</span>\" can't be assigned with <span class="hljs-subst">#{@context}</span> because it has not been declared before"</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">"?"</span> <span class="hljs-keyword">in</span> @context
o.isExistentialEquals = <span class="hljs-literal">true</span>
<span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(left), right, type: <span class="hljs-string">'if'</span>).addElse(<span class="hljs-keyword">new</span> Assign(right, @value, <span class="hljs-string">'='</span>)).compileToFragments o
<span class="hljs-keyword">else</span>
fragments = <span class="hljs-keyword">new</span> Op(@context[...<span class="hljs-number">-1</span>], left, <span class="hljs-keyword">new</span> Assign(right, @value, <span class="hljs-string">'='</span>)).compileToFragments o
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments</pre></div></div>
</li>
<li id="section-213">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-213">&#182;</a>
</div>
<p>Convert special math assignment operators like <code>a **= b</code> to the equivalent
extended form <code>a = a ** b</code> and then compiles that.</p>
</div>
<div class="content"><div class='highlight'><pre> compileSpecialMath: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[left, right] = @variable.cacheReference o
<span class="hljs-keyword">new</span> Assign(left, <span class="hljs-keyword">new</span> Op(@context[...<span class="hljs-number">-1</span>], right, @value)).compileToFragments o</pre></div></div>
</li>
<li id="section-214">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-214">&#182;</a>
</div>
<p>Compile the assignment from an array splice literal, using JavaScripts
<code>Array#splice</code> method.</p>
</div>
<div class="content"><div class='highlight'><pre> compileSplice: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{range: {<span class="hljs-keyword">from</span>, to, exclusive}} = @variable.properties.pop()
unwrappedVar = @variable.unwrapAll()
<span class="hljs-keyword">if</span> unwrappedVar.comments
moveComments unwrappedVar, @
<span class="hljs-keyword">delete</span> @variable.comments
name = @variable.compile o
<span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span>
[fromDecl, fromRef] = @cacheToCodeFragments <span class="hljs-keyword">from</span>.cache o, LEVEL_OP
<span class="hljs-keyword">else</span>
fromDecl = fromRef = <span class="hljs-string">'0'</span>
<span class="hljs-keyword">if</span> to
<span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span>?.isNumber() <span class="hljs-keyword">and</span> to.isNumber()
to = to.compile(o) - fromRef
to += <span class="hljs-number">1</span> <span class="hljs-keyword">unless</span> exclusive
<span class="hljs-keyword">else</span>
to = to.compile(o, LEVEL_ACCESS) + <span class="hljs-string">' - '</span> + fromRef
to += <span class="hljs-string">' + 1'</span> <span class="hljs-keyword">unless</span> exclusive
<span class="hljs-keyword">else</span>
to = <span class="hljs-string">"9e9"</span>
[valDef, valRef] = @value.cache o, LEVEL_LIST
answer = [].concat @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{utility <span class="hljs-string">'splice'</span>, o}</span>.apply(<span class="hljs-subst">#{name}</span>, [<span class="hljs-subst">#{fromDecl}</span>, <span class="hljs-subst">#{to}</span>].concat("</span>), valDef, @makeCode(<span class="hljs-string">")), "</span>), valRef
<span class="hljs-keyword">if</span> o.level &gt; LEVEL_TOP <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
@variable.unwrapAll().eachName iterator</pre></div></div>
</li>
<li id="section-215">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-215">&#182;</a>
</div>
<h3 id="funcglyph">FuncGlyph</h3>
</div>
<div class="content"><div class='highlight'><pre>
exports.FuncGlyph = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FuncGlyph</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@glyph)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()</pre></div></div>
</li>
<li id="section-216">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-216">&#182;</a>
</div>
<h3 id="code">Code</h3>
</div>
</li>
<li id="section-217">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-217">&#182;</a>
</div>
<p>A function definition. This is the only node that creates a new Scope.
When for the purposes of walking the contents of a function body, the Code
has no <em>children</em> theyre within the inner scope.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Code = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(params, body, @funcGlyph, @paramStart)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@params = params <span class="hljs-keyword">or</span> []
@body = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block
@bound = @funcGlyph?.glyph <span class="hljs-keyword">is</span> <span class="hljs-string">'=&gt;'</span>
@isGenerator = <span class="hljs-literal">no</span>
@isAsync = <span class="hljs-literal">no</span>
@isMethod = <span class="hljs-literal">no</span>
@body.traverseChildren <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> (node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.isYield()) <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> YieldReturn
@isGenerator = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">if</span> (node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.isAwait()) <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> AwaitReturn
@isAsync = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">if</span> @isGenerator <span class="hljs-keyword">and</span> @isAsync
node.error <span class="hljs-string">"function can't contain both yield and await"</span>
children: [<span class="hljs-string">'params'</span>, <span class="hljs-string">'body'</span>]
isStatement: <span class="hljs-function">-&gt;</span> @isMethod
jumps: NO
makeScope: <span class="hljs-function"><span class="hljs-params">(parentScope)</span> -&gt;</span> <span class="hljs-keyword">new</span> Scope parentScope, @body, <span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-218">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-218">&#182;</a>
</div>
<p>Compilation creates a new scope unless explicitly asked to share with the
outer scope. Handles splat parameters in the parameter list by setting
such parameters to be the final parameter in the function definition, as
required per the ES2015 spec. If the CoffeeScript function definition had
parameters after the splat, they are declared via expressions in the
function body.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @ctor
@name.error <span class="hljs-string">'Class constructor may not be async'</span> <span class="hljs-keyword">if</span> @isAsync
@name.error <span class="hljs-string">'Class constructor may not be a generator'</span> <span class="hljs-keyword">if</span> @isGenerator
<span class="hljs-keyword">if</span> @bound
@context = o.scope.method.context <span class="hljs-keyword">if</span> o.scope.method?.bound
@context = <span class="hljs-string">'this'</span> <span class="hljs-keyword">unless</span> @context
o.scope = del(o, <span class="hljs-string">'classScope'</span>) <span class="hljs-keyword">or</span> @makeScope o.scope
o.scope.shared = del(o, <span class="hljs-string">'sharedScope'</span>)
o.indent += TAB
<span class="hljs-keyword">delete</span> o.bare
<span class="hljs-keyword">delete</span> o.isExistentialEquals
params = []
exprs = []
thisAssignments = @thisAssignments?.slice() ? []
paramsAfterSplat = []
haveSplatParam = <span class="hljs-literal">no</span>
haveBodyParam = <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-219">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-219">&#182;</a>
</div>
<p>Check for duplicate parameters and separate <code>this</code> assignments.</p>
</div>
<div class="content"><div class='highlight'><pre> paramNames = []
@eachParamName (name, node, param, obj) -&gt;
node.error <span class="hljs-string">"multiple parameters named '<span class="hljs-subst">#{name}</span>'"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> paramNames
paramNames.push name
<span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span>
name = node.properties[<span class="hljs-number">0</span>].name.value
name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN
target = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable name, reserve: <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-220">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-220">&#182;</a>
</div>
<p><code>Param</code> is object destructuring with a default value: ({@prop = 1}) -&gt;
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}) -&gt;</p>
</div>
<div class="content"><div class='highlight'><pre> replacement =
<span class="hljs-keyword">if</span> param.name <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span>
obj.operatorToken.value <span class="hljs-keyword">is</span> <span class="hljs-string">'='</span>
<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> IdentifierLiteral name), target, <span class="hljs-string">'object'</span> <span class="hljs-comment">#, operatorToken: new Literal ':'</span>
<span class="hljs-keyword">else</span>
target
param.renameParam node, replacement
thisAssignments.push <span class="hljs-keyword">new</span> Assign node, target</pre></div></div>
</li>
<li id="section-221">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-221">&#182;</a>
</div>
<p>Parse the parameters, adding them to the list of parameters to put in the
function definition; and dealing with splats or expansions, including
adding expressions to the function body to declare all parameter
variables that would have been after the splat/expansion parameter.
If we encounter a parameter that needs to be declared in the function
body for any reason, for example its destructured with <code>this</code>, also
declare and assign all subsequent parameters in the function body so that
any non-idempotent parameters are evaluated in the correct order.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> param, i <span class="hljs-keyword">in</span> @params</pre></div></div>
</li>
<li id="section-222">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-222">&#182;</a>
</div>
<p>Was <code>...</code> used with this parameter? (Only one such parameter is allowed
per function.) Splat/expansion parameters cannot have default values,
so we need not worry about that.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.splat <span class="hljs-keyword">or</span> param <span class="hljs-keyword">instanceof</span> Expansion
<span class="hljs-keyword">if</span> haveSplatParam
param.error <span class="hljs-string">'only one splat or expansion parameter is allowed per function definition'</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> param <span class="hljs-keyword">instanceof</span> Expansion <span class="hljs-keyword">and</span> @params.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
param.error <span class="hljs-string">'an expansion parameter cannot be the only parameter in a function definition'</span>
haveSplatParam = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">if</span> param.splat
<span class="hljs-keyword">if</span> param.name <span class="hljs-keyword">instanceof</span> Arr</pre></div></div>
</li>
<li id="section-223">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-223">&#182;</a>
</div>
<p>Splat arrays are treated oddly by ES; deal with them the legacy
way in the function body. TODO: Should this be handled in the
function parameter list, and if so, how?</p>
</div>
<div class="content"><div class='highlight'><pre> splatParamName = o.scope.freeVariable <span class="hljs-string">'arg'</span>
params.push ref = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral splatParamName
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), ref
<span class="hljs-keyword">else</span>
params.push ref = param.asReference o
splatParamName = fragmentsToText ref.compileNodeWithoutComments o
<span class="hljs-keyword">if</span> param.shouldCache()
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), ref
<span class="hljs-keyword">else</span> <span class="hljs-comment"># `param` is an Expansion</span>
splatParamName = o.scope.freeVariable <span class="hljs-string">'args'</span>
params.push <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral splatParamName
o.scope.parameter splatParamName</pre></div></div>
</li>
<li id="section-224">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-224">&#182;</a>
</div>
<p>Parse all other parameters; if a splat paramater has not yet been
encountered, add these other parameters to the list to be output in
the function definition.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> param.shouldCache() <span class="hljs-keyword">or</span> haveBodyParam
param.assignedInBody = <span class="hljs-literal">yes</span>
haveBodyParam = <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-225">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-225">&#182;</a>
</div>
<p>This parameter cannot be declared or assigned in the parameter
list. So put a reference in the parameter list and add a statement
to the function body assigning it, e.g.
<code>(arg) =&gt; { var a = arg.a; }</code>, with a default value if it has one.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.value?
condition = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'==='</span>, param, <span class="hljs-keyword">new</span> UndefinedLiteral
ifTrue = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.value
exprs.push <span class="hljs-keyword">new</span> If condition, ifTrue
<span class="hljs-keyword">else</span>
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.asReference(o), <span class="hljs-literal">null</span>, param: <span class="hljs-string">'alwaysDeclare'</span></pre></div></div>
</li>
<li id="section-226">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-226">&#182;</a>
</div>
<p>If this parameter comes before the splat or expansion, it will go
in the function definition parameter list.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> haveSplatParam</pre></div></div>
</li>
<li id="section-227">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-227">&#182;</a>
</div>
<p>If this parameter has a default value, and it hasnt already been
set by the <code>shouldCache()</code> block above, define it as a statement in
the function body. This parameter comes after the splat parameter,
so we cant define its default value in the parameter list.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.shouldCache()
ref = param.asReference o
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> param.assignedInBody
ref = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.value, <span class="hljs-literal">null</span>, param: <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
ref = param</pre></div></div>
</li>
<li id="section-228">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-228">&#182;</a>
</div>
<p>Add this parameters reference(s) to the function scope.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.name <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> param.name <span class="hljs-keyword">instanceof</span> Obj</pre></div></div>
</li>
<li id="section-229">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-229">&#182;</a>
</div>
<p>This parameter is destructured.</p>
</div>
<div class="content"><div class='highlight'><pre> param.name.lhs = <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-230">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-230">&#182;</a>
</div>
<p>Compile <code>foo({a, b...}) -&gt;</code> to <code>foo(arg) -&gt; {a, b...} = arg</code>.
Can be removed once ES proposal hits Stage 4.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.name <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> param.name.hasSplat()
splatParamName = o.scope.freeVariable <span class="hljs-string">'arg'</span>
o.scope.parameter splatParamName
ref = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral splatParamName
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), ref, <span class="hljs-literal">null</span>, param: <span class="hljs-string">'alwaysDeclare'</span></pre></div></div>
</li>
<li id="section-231">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-231">&#182;</a>
</div>
<p>Compile <code>foo({a, b...} = {}) -&gt;</code> to <code>foo(arg = {}) -&gt; {a, b...} = arg</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> param.assignedInBody
ref = <span class="hljs-keyword">new</span> Assign ref, param.value, <span class="hljs-literal">null</span>, param: <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">unless</span> param.shouldCache()
param.name.eachName (prop) -&gt;
o.scope.parameter prop.value
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-232">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-232">&#182;</a>
</div>
<p>This compilation of the parameter is only to get its name to add
to the scope name tracking; since the compilation output here
isnt kept for eventual output, dont include comments in this
compilation, so that they get output the “real” time this param
is compiled.</p>
</div>
<div class="content"><div class='highlight'><pre> paramToAddToScope = <span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">then</span> param <span class="hljs-keyword">else</span> ref
o.scope.parameter fragmentsToText paramToAddToScope.compileToFragmentsWithoutComments o
params.push ref
<span class="hljs-keyword">else</span>
paramsAfterSplat.push param</pre></div></div>
</li>
<li id="section-233">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-233">&#182;</a>
</div>
<p>If this parameter had a default value, since its no longer in the
function parameter list we need to assign its default value
(if necessary) as an expression in the body.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> param.shouldCache()
condition = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'==='</span>, param, <span class="hljs-keyword">new</span> UndefinedLiteral
ifTrue = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.value
exprs.push <span class="hljs-keyword">new</span> If condition, ifTrue</pre></div></div>
</li>
<li id="section-234">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-234">&#182;</a>
</div>
<p>Add this parameter to the scope, since it wouldnt have been added
yet since it was skipped earlier.</p>
</div>
<div class="content"><div class='highlight'><pre> o.scope.add param.name.value, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> param.name?.value?</pre></div></div>
</li>
<li id="section-235">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-235">&#182;</a>
</div>
<p>If there were parameters after the splat or expansion parameter, those
parameters need to be assigned in the body of the function.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> paramsAfterSplat.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span></pre></div></div>
</li>
<li id="section-236">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-236">&#182;</a>
</div>
<p>Create a destructured assignment, e.g. <code>[a, b, c] = [args..., b, c]</code></p>
</div>
<div class="content"><div class='highlight'><pre> exprs.unshift <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(
<span class="hljs-keyword">new</span> Arr [<span class="hljs-keyword">new</span> Splat(<span class="hljs-keyword">new</span> IdentifierLiteral(splatParamName)), (param.asReference o <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> paramsAfterSplat)...]
), <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral splatParamName</pre></div></div>
</li>
<li id="section-237">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-237">&#182;</a>
</div>
<p>Add new expressions to the function body</p>
</div>
<div class="content"><div class='highlight'><pre> wasEmpty = @body.isEmpty()
@body.expressions.unshift thisAssignments... <span class="hljs-keyword">unless</span> @expandCtorSuper thisAssignments
@body.expressions.unshift exprs...
<span class="hljs-keyword">if</span> @isMethod <span class="hljs-keyword">and</span> @bound <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @isStatic <span class="hljs-keyword">and</span> @classVariable
boundMethodCheck = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'boundMethodCheck'</span>, o
@body.expressions.unshift <span class="hljs-keyword">new</span> Call(boundMethodCheck, [<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> ThisLiteral), @classVariable])
@body.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> @noReturn</pre></div></div>
</li>
<li id="section-238">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-238">&#182;</a>
</div>
<p>JavaScript doesnt allow bound (<code>=&gt;</code>) functions to also be generators.
This is usually caught via <code>Op::compileContinuation</code>, but double-check:</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @bound <span class="hljs-keyword">and</span> @isGenerator
yieldNode = @body.contains (node) -&gt; node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.operator <span class="hljs-keyword">is</span> <span class="hljs-string">'yield'</span>
(yieldNode <span class="hljs-keyword">or</span> @).error <span class="hljs-string">'yield cannot occur inside bound (fat arrow) functions'</span></pre></div></div>
</li>
<li id="section-239">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-239">&#182;</a>
</div>
<p>Assemble the output</p>
</div>
<div class="content"><div class='highlight'><pre> modifiers = []
modifiers.push <span class="hljs-string">'static'</span> <span class="hljs-keyword">if</span> @isMethod <span class="hljs-keyword">and</span> @isStatic
modifiers.push <span class="hljs-string">'async'</span> <span class="hljs-keyword">if</span> @isAsync
<span class="hljs-keyword">unless</span> @isMethod <span class="hljs-keyword">or</span> @bound
modifiers.push <span class="hljs-string">"function<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isGenerator <span class="hljs-keyword">then</span> <span class="hljs-string">'*'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @isGenerator
modifiers.push <span class="hljs-string">'*'</span>
signature = [@makeCode <span class="hljs-string">'('</span>]</pre></div></div>
</li>
<li id="section-240">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-240">&#182;</a>
</div>
<p>Block comments between a function name and <code>(</code> get output between
<code>function</code> and <code>(</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @paramStart?.comments?
@compileCommentFragments o, @paramStart, signature
<span class="hljs-keyword">for</span> param, i <span class="hljs-keyword">in</span> params
signature.push @makeCode <span class="hljs-string">', '</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
signature.push @makeCode <span class="hljs-string">'...'</span> <span class="hljs-keyword">if</span> haveSplatParam <span class="hljs-keyword">and</span> i <span class="hljs-keyword">is</span> params.length - <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-241">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-241">&#182;</a>
</div>
<p>Compile this parameter, but if any generated variables get created
(e.g. <code>ref</code>), shift those into the parent scope since we cant put a
<code>var</code> line inside a function parameter list.</p>
</div>
<div class="content"><div class='highlight'><pre> scopeVariablesCount = o.scope.variables.length
signature.push param.compileToFragments(o)...
<span class="hljs-keyword">if</span> scopeVariablesCount <span class="hljs-keyword">isnt</span> o.scope.variables.length
generatedVariables = o.scope.variables.splice scopeVariablesCount
o.scope.parent.variables.push generatedVariables...
signature.push @makeCode <span class="hljs-string">')'</span></pre></div></div>
</li>
<li id="section-242">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-242">&#182;</a>
</div>
<p>Block comments between <code>)</code> and <code>-&gt;</code>/<code>=&gt;</code> get output between <code>)</code> and <code>{</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @funcGlyph?.comments?
comment.unshift = <span class="hljs-literal">no</span> <span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> @funcGlyph.comments
@compileCommentFragments o, @funcGlyph, signature
body = @body.compileWithDeclarations o <span class="hljs-keyword">unless</span> @body.isEmpty()</pre></div></div>
</li>
<li id="section-243">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-243">&#182;</a>
</div>
<p>We need to compile the body before method names to ensure <code>super</code>
references are handled.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @isMethod
[methodScope, o.scope] = [o.scope, o.scope.parent]
name = @name.compileToFragments o
name.shift() <span class="hljs-keyword">if</span> name[<span class="hljs-number">0</span>].code <span class="hljs-keyword">is</span> <span class="hljs-string">'.'</span>
o.scope = methodScope
answer = @joinFragmentArrays (@makeCode m <span class="hljs-keyword">for</span> m <span class="hljs-keyword">in</span> modifiers), <span class="hljs-string">' '</span>
answer.push @makeCode <span class="hljs-string">' '</span> <span class="hljs-keyword">if</span> modifiers.length <span class="hljs-keyword">and</span> name
answer.push name... <span class="hljs-keyword">if</span> name
answer.push signature...
answer.push @makeCode <span class="hljs-string">' =&gt;'</span> <span class="hljs-keyword">if</span> @bound <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @isMethod
answer.push @makeCode <span class="hljs-string">' {'</span>
answer.push @makeCode(<span class="hljs-string">'\n'</span>), body..., @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>) <span class="hljs-keyword">if</span> body?.length
answer.push @makeCode <span class="hljs-string">'}'</span>
<span class="hljs-keyword">return</span> indentInitial answer, @ <span class="hljs-keyword">if</span> @isMethod
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">or</span> (o.level &gt;= LEVEL_ACCESS) <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer
eachParamName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
param.eachName iterator <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params</pre></div></div>
</li>
<li id="section-244">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-244">&#182;</a>
</div>
<p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope
boundaries unless <code>crossScope</code> is <code>true</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> traverseChildren: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -&gt;</span>
<span class="hljs-keyword">super</span>(crossScope, func) <span class="hljs-keyword">if</span> crossScope</pre></div></div>
</li>
<li id="section-245">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-245">&#182;</a>
</div>
<p>Short-circuit <code>replaceInContext</code> method to prevent it from crossing context boundaries. Bound
functions have the same context.</p>
</div>
<div class="content"><div class='highlight'><pre> replaceInContext: <span class="hljs-function"><span class="hljs-params">(child, replacement)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @bound
<span class="hljs-keyword">super</span> child, replacement
<span class="hljs-keyword">else</span>
<span class="hljs-literal">false</span>
expandCtorSuper: <span class="hljs-function"><span class="hljs-params">(thisAssignments)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">unless</span> @ctor
@eachSuperCall Block.wrap(@params), <span class="hljs-function"><span class="hljs-params">(superCall)</span> -&gt;</span>
superCall.error <span class="hljs-string">"'super' is not allowed in constructor parameter defaults"</span>
seenSuper = @eachSuperCall @body, <span class="hljs-function"><span class="hljs-params">(superCall)</span> =&gt;</span>
superCall.error <span class="hljs-string">"'super' is only allowed in derived class constructors"</span> <span class="hljs-keyword">if</span> @ctor <span class="hljs-keyword">is</span> <span class="hljs-string">'base'</span>
superCall.expressions = thisAssignments
haveThisParam = thisAssignments.length <span class="hljs-keyword">and</span> thisAssignments.length <span class="hljs-keyword">isnt</span> @thisAssignments?.length
<span class="hljs-keyword">if</span> @ctor <span class="hljs-keyword">is</span> <span class="hljs-string">'derived'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> seenSuper <span class="hljs-keyword">and</span> haveThisParam
param = thisAssignments[<span class="hljs-number">0</span>].variable
param.error <span class="hljs-string">"Can't use @params in derived class constructors without calling super"</span>
seenSuper</pre></div></div>
</li>
<li id="section-246">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-246">&#182;</a>
</div>
<p>Find all super calls in the given context node;
returns <code>true</code> if <code>iterator</code> is called.</p>
</div>
<div class="content"><div class='highlight'><pre> eachSuperCall: <span class="hljs-function"><span class="hljs-params">(context, iterator)</span> -&gt;</span>
seenSuper = <span class="hljs-literal">no</span>
context.traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =&gt;</span>
<span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> SuperCall</pre></div></div>
</li>
<li id="section-247">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-247">&#182;</a>
</div>
<p><code>super</code> in a constructor (the only <code>super</code> without an accessor)
cannot be given an argument with a reference to <code>this</code>, as that would
be referencing <code>this</code> before calling <code>super</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> child.variable.accessor
childArgs = child.args.filter (arg) -&gt;
arg <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">and</span> (arg <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">or</span> arg.bound)
Block.wrap(childArgs).traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
node.error <span class="hljs-string">"Can't call super with @params in derived class constructors"</span> <span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span>
seenSuper = <span class="hljs-literal">yes</span>
iterator child
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">and</span> @ctor <span class="hljs-keyword">is</span> <span class="hljs-string">'derived'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> seenSuper
child.error <span class="hljs-string">"Can't reference 'this' before calling super in derived class constructors"</span></pre></div></div>
</li>
<li id="section-248">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-248">&#182;</a>
</div>
<p><code>super</code> has the same target in bound (arrow) functions, so check them too</p>
</div>
<div class="content"><div class='highlight'><pre> child <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> SuperCall <span class="hljs-keyword">and</span> (child <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">or</span> child.bound)
seenSuper</pre></div></div>
</li>
<li id="section-249">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-249">&#182;</a>
</div>
<h3 id="param">Param</h3>
</div>
</li>
<li id="section-250">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-250">&#182;</a>
</div>
<p>A parameter in a function definition. Beyond a typical JavaScript parameter,
these parameters can also attach themselves to the context of the function,
as well as be a splat, gathering up a group of parameters into an array.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Param = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Param</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@name, @value, @splat)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
message = isUnassignable @name.unwrapAll().value
@name.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">if</span> @name <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> @name.generated
token = @name.objects[<span class="hljs-number">0</span>].operatorToken
token.error <span class="hljs-string">"unexpected <span class="hljs-subst">#{token.value}</span>"</span>
children: [<span class="hljs-string">'name'</span>, <span class="hljs-string">'value'</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragments o, LEVEL_LIST
compileToFragmentsWithoutComments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragmentsWithoutComments o, LEVEL_LIST
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> @reference <span class="hljs-keyword">if</span> @reference
node = @name
<span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span>
name = node.properties[<span class="hljs-number">0</span>].name.value
name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN
node = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.shouldCache()
node = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'arg'</span>
node = <span class="hljs-keyword">new</span> Value node
node.updateLocationDataIfMissing @locationData
@reference = node
shouldCache: <span class="hljs-function">-&gt;</span>
@name.shouldCache()</pre></div></div>
</li>
<li id="section-251">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-251">&#182;</a>
</div>
<p>Iterates the name or names of a <code>Param</code>.
In a sense, a destructured parameter represents multiple JS parameters. This
method allows to iterate them all.
The <code>iterator</code> function will be called as <code>iterator(name, node)</code> where
<code>name</code> is the name of the parameter and <code>node</code> is the AST node corresponding
to that name.</p>
</div>
<div class="content"><div class='highlight'><pre> eachName: <span class="hljs-function"><span class="hljs-params">(iterator, name = @name)</span> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">atParam</span> = <span class="hljs-params">(obj, originalObj = <span class="hljs-literal">null</span>)</span> =&gt;</span> iterator <span class="hljs-string">"@<span class="hljs-subst">#{obj.properties[<span class="hljs-number">0</span>].name.value}</span>"</span>, obj, @, originalObj</pre></div></div>
</li>
<li id="section-252">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-252">&#182;</a>
</div>
<ul>
<li>simple literals <code>foo</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> iterator name.value, name, @ <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Literal</pre></div></div>
</li>
<li id="section-253">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-253">&#182;</a>
</div>
<ul>
<li>at-params <code>@foo</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> atParam name <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Value
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> name.objects ? []</pre></div></div>
</li>
<li id="section-254">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-254">&#182;</a>
</div>
<p>Save original obj.</p>
</div>
<div class="content"><div class='highlight'><pre> nObj = obj</pre></div></div>
</li>
<li id="section-255">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-255">&#182;</a>
</div>
<ul>
<li>destructured parameter with default value</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> obj.context?
obj = obj.variable</pre></div></div>
</li>
<li id="section-256">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-256">&#182;</a>
</div>
<ul>
<li>assignments within destructured parameters <code>{foo:bar}</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign</pre></div></div>
</li>
<li id="section-257">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-257">&#182;</a>
</div>
<p>… possibly with a default value</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.value <span class="hljs-keyword">instanceof</span> Assign
obj = obj.value.variable
<span class="hljs-keyword">else</span>
obj = obj.value
@eachName iterator, obj.unwrap()</pre></div></div>
</li>
<li id="section-258">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-258">&#182;</a>
</div>
<ul>
<li>splats within destructured parameters <code>[xs...]</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat
node = obj.name.unwrap()
iterator node.value, node, @
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Value</pre></div></div>
</li>
<li id="section-259">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-259">&#182;</a>
</div>
<ul>
<li>destructured parameters within destructured parameters <code>[{a}]</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.isArray() <span class="hljs-keyword">or</span> obj.isObject()
@eachName iterator, obj.base</pre></div></div>
</li>
<li id="section-260">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-260">&#182;</a>
</div>
<ul>
<li>at-params within destructured parameters <code>{@foo}</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
atParam obj, nObj</pre></div></div>
</li>
<li id="section-261">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-261">&#182;</a>
</div>
<ul>
<li>simple destructured parameters {foo}</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> iterator obj.base.value, obj.base, @
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Elision
obj
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">"illegal parameter <span class="hljs-subst">#{obj.compile()}</span>"</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
<li id="section-262">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-262">&#182;</a>
</div>
<p>Rename a param by replacing the given AST node for a name with a new node.
This needs to ensure that the the source for object destructuring does not change.</p>
</div>
<div class="content"><div class='highlight'><pre> renameParam: <span class="hljs-function"><span class="hljs-params">(node, newNode)</span> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">isNode</span> = <span class="hljs-params">(candidate)</span> -&gt;</span> candidate <span class="hljs-keyword">is</span> node
<span class="hljs-function"> <span class="hljs-title">replacement</span> = <span class="hljs-params">(node, parent)</span> =&gt;</span>
<span class="hljs-keyword">if</span> parent <span class="hljs-keyword">instanceof</span> Obj
key = node
key = node.properties[<span class="hljs-number">0</span>].name <span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-263">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-263">&#182;</a>
</div>
<p>No need to assign a new variable for the destructured variable if the variable isnt reserved.
Examples:
<code>({@foo}) -&gt;</code> should compile to <code>({foo}) { this.foo = foo}</code>
<code>foo = 1; ({@foo}) -&gt;</code> should compile to <code>foo = 1; ({foo:foo1}) { this.foo = foo1 }</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span> <span class="hljs-keyword">and</span> key.value <span class="hljs-keyword">is</span> newNode.value
<span class="hljs-keyword">new</span> Value newNode
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(key), newNode, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">else</span>
newNode
@replaceInContext isNode, replacement</pre></div></div>
</li>
<li id="section-264">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-264">&#182;</a>
</div>
<h3 id="splat">Splat</h3>
</div>
</li>
<li id="section-265">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-265">&#182;</a>
</div>
<p>A splat, either as a parameter to a function, an argument to a call,
or as part of a destructuring assignment.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Splat = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Splat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@name = <span class="hljs-keyword">if</span> name.compile <span class="hljs-keyword">then</span> name <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Literal name
children: [<span class="hljs-string">'name'</span>]
isAssignable: <span class="hljs-function">-&gt;</span>
@name.isAssignable() <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> @name.isAtomic <span class="hljs-keyword">or</span> @name.isAtomic())
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@name.assigns name
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">'...'</span>), @name.compileToFragments(o, LEVEL_OP)...]
unwrap: <span class="hljs-function">-&gt;</span> @name</pre></div></div>
</li>
<li id="section-266">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-266">&#182;</a>
</div>
<h3 id="expansion">Expansion</h3>
</div>
</li>
<li id="section-267">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-267">&#182;</a>
</div>
<p>Used to skip values inside an array destructuring (pattern matching) or
parameter list.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Expansion = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expansion</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
shouldCache: NO
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@error <span class="hljs-string">'Expansion must be used inside a destructuring assignment or parameter list'</span>
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">this</span>
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-268">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-268">&#182;</a>
</div>
<h3 id="elision">Elision</h3>
</div>
</li>
<li id="section-269">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-269">&#182;</a>
</div>
<p>Array elision element (for example, [,a, , , b, , c, ,]).</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Elision = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Elision</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
isAssignable: YES
shouldCache: NO
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
fragment = <span class="hljs-keyword">super</span> o, level
fragment.isElision = <span class="hljs-literal">yes</span>
fragment
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-string">', '</span>]
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">this</span>
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-270">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-270">&#182;</a>
</div>
<h3 id="while">While</h3>
</div>
</li>
<li id="section-271">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-271">&#182;</a>
</div>
<p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
it, all other loops can be manufactured. Useful in cases where you need more
flexibility or more speed than a comprehension can provide.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.While = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">While</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(condition, options)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@condition = <span class="hljs-keyword">if</span> options?.invert <span class="hljs-keyword">then</span> condition.invert() <span class="hljs-keyword">else</span> condition
@guard = options?.guard
children: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'body'</span>]
isStatement: YES
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
<span class="hljs-keyword">if</span> res
<span class="hljs-keyword">super</span> res
<span class="hljs-keyword">else</span>
@returns = <span class="hljs-keyword">not</span> @jumps()
<span class="hljs-keyword">this</span>
addBody: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
<span class="hljs-keyword">this</span>
jumps: <span class="hljs-function">-&gt;</span>
{expressions} = @body
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> expressions.length
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> expressions
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = node.jumps loop: <span class="hljs-literal">yes</span>
<span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-272">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-272">&#182;</a>
</div>
<p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
<em>while</em> can be used as a part of a larger expression while loops may
return an array containing the computed result of each iteration.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.indent += TAB
set = <span class="hljs-string">''</span>
{body} = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">if</span> body.isEmpty()
body = @makeCode <span class="hljs-string">''</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> @returns
body.makeReturn rvar = o.scope.freeVariable <span class="hljs-string">'results'</span>
set = <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span>
<span class="hljs-keyword">if</span> @guard
<span class="hljs-keyword">if</span> body.expressions.length &gt; <span class="hljs-number">1</span>
body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens @guard).invert(), <span class="hljs-keyword">new</span> StatementLiteral <span class="hljs-string">"continue"</span>
<span class="hljs-keyword">else</span>
body = Block.wrap [<span class="hljs-keyword">new</span> If @guard, body] <span class="hljs-keyword">if</span> @guard
body = [].concat @makeCode(<span class="hljs-string">"\n"</span>), (body.compileToFragments o, LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>)
answer = [].concat @makeCode(set + @tab + <span class="hljs-string">"while ("</span>), @condition.compileToFragments(o, LEVEL_PAREN),
@makeCode(<span class="hljs-string">") {"</span>), body, @makeCode(<span class="hljs-string">"}"</span>)
<span class="hljs-keyword">if</span> @returns
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;"</span>
answer</pre></div></div>
</li>
<li id="section-273">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-273">&#182;</a>
</div>
<h3 id="op">Op</h3>
</div>
</li>
<li id="section-274">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-274">&#182;</a>
</div>
<p>Simple Arithmetic and logical operations. Performs some conversion from
CoffeeScript operations into their JavaScript equivalents.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Op = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Op</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(op, first, second, flip)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> In first, second <span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'in'</span>
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'do'</span>
<span class="hljs-keyword">return</span> Op::generateDo first
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span>
<span class="hljs-keyword">if</span> (firstCall = first.unwrap()) <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> firstCall.<span class="hljs-keyword">do</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> firstCall.isNew
<span class="hljs-keyword">return</span> firstCall.newInstance()
first = <span class="hljs-keyword">new</span> Parens first <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> first.bound <span class="hljs-keyword">or</span> first.<span class="hljs-keyword">do</span>
@operator = CONVERSIONS[op] <span class="hljs-keyword">or</span> op
@first = first
@second = second
@flip = !!flip
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-275">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-275">&#182;</a>
</div>
<p>The map of conversions from CoffeeScript to JavaScript symbols.</p>
</div>
<div class="content"><div class='highlight'><pre> CONVERSIONS =
<span class="hljs-string">'=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'!='</span>: <span class="hljs-string">'!=='</span>
<span class="hljs-string">'of'</span>: <span class="hljs-string">'in'</span>
<span class="hljs-string">'yieldfrom'</span>: <span class="hljs-string">'yield*'</span></pre></div></div>
</li>
<li id="section-276">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-276">&#182;</a>
</div>
<p>The map of invertible operators.</p>
</div>
<div class="content"><div class='highlight'><pre> INVERSIONS =
<span class="hljs-string">'!=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'==='</span>: <span class="hljs-string">'!=='</span>
children: [<span class="hljs-string">'first'</span>, <span class="hljs-string">'second'</span>]
isNumber: <span class="hljs-function">-&gt;</span>
@isUnary() <span class="hljs-keyword">and</span> @operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>] <span class="hljs-keyword">and</span>
@first <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @first.isNumber()
isAwait: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">is</span> <span class="hljs-string">'await'</span>
isYield: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>]
isUnary: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @second
shouldCache: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @isNumber()</pre></div></div>
</li>
<li id="section-277">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-277">&#182;</a>
</div>
<p>Am I capable of
<a href="https://docs.python.org/3/reference/expressions.html#not-in">Python-style comparison chaining</a>?</p>
</div>
<div class="content"><div class='highlight'><pre> isChainable: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'&lt;'</span>, <span class="hljs-string">'&gt;'</span>, <span class="hljs-string">'&gt;='</span>, <span class="hljs-string">'&lt;='</span>, <span class="hljs-string">'==='</span>, <span class="hljs-string">'!=='</span>]
invert: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isChainable() <span class="hljs-keyword">and</span> @first.isChainable()
allInvertable = <span class="hljs-literal">yes</span>
curr = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator
allInvertable <span class="hljs-keyword">and</span>= (curr.operator <span class="hljs-keyword">of</span> INVERSIONS)
curr = curr.first
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert() <span class="hljs-keyword">unless</span> allInvertable
curr = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator
curr.invert = !curr.invert
curr.operator = INVERSIONS[curr.operator]
curr = curr.first
<span class="hljs-keyword">this</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> op = INVERSIONS[@operator]
@operator = op
<span class="hljs-keyword">if</span> @first.unwrap() <span class="hljs-keyword">instanceof</span> Op
@first.invert()
<span class="hljs-keyword">this</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @second
<span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert()
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">and</span> (fst = @first.unwrap()) <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span>
fst.operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'!'</span>, <span class="hljs-string">'in'</span>, <span class="hljs-string">'instanceof'</span>]
fst
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span>
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'++'</span>, <span class="hljs-string">'--'</span>, <span class="hljs-string">'delete'</span>] <span class="hljs-keyword">and</span> unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'first'</span>
generateDo: <span class="hljs-function"><span class="hljs-params">(exp)</span> -&gt;</span>
passedParams = []
func = <span class="hljs-keyword">if</span> exp <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> (ref = exp.value.unwrap()) <span class="hljs-keyword">instanceof</span> Code
ref
<span class="hljs-keyword">else</span>
exp
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> func.params <span class="hljs-keyword">or</span> []
<span class="hljs-keyword">if</span> param.value
passedParams.push param.value
<span class="hljs-keyword">delete</span> param.value
<span class="hljs-keyword">else</span>
passedParams.push param
call = <span class="hljs-keyword">new</span> Call exp, passedParams
call.<span class="hljs-keyword">do</span> = <span class="hljs-literal">yes</span>
call
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
isChain = @isChainable() <span class="hljs-keyword">and</span> @first.isChainable()</pre></div></div>
</li>
<li id="section-278">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-278">&#182;</a>
</div>
<p>In chains, theres no need to wrap bare obj literals in parens,
as the chained expression is wrapped.</p>
</div>
<div class="content"><div class='highlight'><pre> @first.front = @front <span class="hljs-keyword">unless</span> isChain
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">'delete'</span> <span class="hljs-keyword">and</span> o.scope.check(@first.unwrapAll().value)
@error <span class="hljs-string">'delete operand may not be argument or var'</span>
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>]
message = isUnassignable @first.unwrapAll().value
@first.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">return</span> @compileContinuation o <span class="hljs-keyword">if</span> @isYield() <span class="hljs-keyword">or</span> @isAwait()
<span class="hljs-keyword">return</span> @compileUnary o <span class="hljs-keyword">if</span> @isUnary()
<span class="hljs-keyword">return</span> @compileChain o <span class="hljs-keyword">if</span> isChain
<span class="hljs-keyword">switch</span> @operator
<span class="hljs-keyword">when</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">then</span> @compileExistence o, @second.isDefaultValue
<span class="hljs-keyword">when</span> <span class="hljs-string">'**'</span> <span class="hljs-keyword">then</span> @compilePower o
<span class="hljs-keyword">when</span> <span class="hljs-string">'//'</span> <span class="hljs-keyword">then</span> @compileFloorDivision o
<span class="hljs-keyword">when</span> <span class="hljs-string">'%%'</span> <span class="hljs-keyword">then</span> @compileModulo o
<span class="hljs-keyword">else</span>
lhs = @first.compileToFragments o, LEVEL_OP
rhs = @second.compileToFragments o, LEVEL_OP
answer = [].concat lhs, @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{@operator}</span> "</span>), rhs
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_OP <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> @wrapInParentheses answer</pre></div></div>
</li>
<li id="section-279">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-279">&#182;</a>
</div>
<p>Mimic Pythons chained comparisons when multiple comparison operators are
used sequentially. For example:</p>
<pre><code>bin/coffee -e <span class="hljs-string">'console.log 50 &lt; 65 &gt; 10'</span>
<span class="hljs-literal">true</span>
</code></pre>
</div>
<div class="content"><div class='highlight'><pre> compileChain: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@first.second, shared] = @first.second.cache o
fst = @first.compileToFragments o, LEVEL_OP
fragments = fst.concat @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @invert <span class="hljs-keyword">then</span> <span class="hljs-string">'&amp;&amp;'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'||'</span>}</span> "</span>),
(shared.compileToFragments o), @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{@operator}</span> "</span>), (@second.compileToFragments o, LEVEL_OP)
@wrapInParentheses fragments</pre></div></div>
</li>
<li id="section-280">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-280">&#182;</a>
</div>
<p>Keep reference to the left expression, unless this an existential assignment</p>
</div>
<div class="content"><div class='highlight'><pre> compileExistence: <span class="hljs-function"><span class="hljs-params">(o, checkOnlyUndefined)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @first.shouldCache()
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
fst = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign ref, @first
<span class="hljs-keyword">else</span>
fst = @first
ref = fst
<span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(fst, checkOnlyUndefined), ref, type: <span class="hljs-string">'if'</span>).addElse(@second).compileToFragments o</pre></div></div>
</li>
<li id="section-281">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-281">&#182;</a>
</div>
<p>Compile a unary <strong>Op</strong>.</p>
</div>
<div class="content"><div class='highlight'><pre> compileUnary: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
parts = []
op = @operator
parts.push [@makeCode op]
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Existence
@first.negated = <span class="hljs-keyword">not</span> @first.negated
<span class="hljs-keyword">return</span> @first.compileToFragments o
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_ACCESS
<span class="hljs-keyword">return</span> (<span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">this</span>).compileToFragments o
plusMinus = op <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>]
parts.push [@makeCode(<span class="hljs-string">' '</span>)] <span class="hljs-keyword">if</span> op <span class="hljs-keyword">in</span> [<span class="hljs-string">'new'</span>, <span class="hljs-string">'typeof'</span>, <span class="hljs-string">'delete'</span>] <span class="hljs-keyword">or</span>
plusMinus <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> @first.operator <span class="hljs-keyword">is</span> op
<span class="hljs-keyword">if</span> (plusMinus <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Op) <span class="hljs-keyword">or</span> (op <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span> <span class="hljs-keyword">and</span> @first.isStatement o)
@first = <span class="hljs-keyword">new</span> Parens @first
parts.push @first.compileToFragments o, LEVEL_OP
parts.reverse() <span class="hljs-keyword">if</span> @flip
@joinFragmentArrays parts, <span class="hljs-string">''</span>
compileContinuation: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
parts = []
op = @operator
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">"<span class="hljs-subst">#{@operator}</span> can only occur inside functions"</span>
<span class="hljs-keyword">if</span> o.scope.method?.bound <span class="hljs-keyword">and</span> o.scope.method.isGenerator
@error <span class="hljs-string">'yield cannot occur inside bound (fat arrow) functions'</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">'expression'</span> <span class="hljs-keyword">in</span> Object.keys(@first) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@first <span class="hljs-keyword">instanceof</span> Throw)
parts.push @first.expression.compileToFragments o, LEVEL_OP <span class="hljs-keyword">if</span> @first.expression?
<span class="hljs-keyword">else</span>
parts.push [@makeCode <span class="hljs-string">"("</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
parts.push [@makeCode op]
parts.push [@makeCode <span class="hljs-string">" "</span>] <span class="hljs-keyword">if</span> @first.base?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">''</span>
parts.push @first.compileToFragments o, LEVEL_OP
parts.push [@makeCode <span class="hljs-string">")"</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
@joinFragmentArrays parts, <span class="hljs-string">''</span>
compilePower: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-282">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-282">&#182;</a>
</div>
<p>Make a Math.pow call</p>
</div>
<div class="content"><div class='highlight'><pre> pow = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'pow'</span>]
<span class="hljs-keyword">new</span> Call(pow, [@first, @second]).compileToFragments o
compileFloorDivision: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
floor = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'floor'</span>]
second = <span class="hljs-keyword">if</span> @second.shouldCache() <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Parens @second <span class="hljs-keyword">else</span> @second
div = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'/'</span>, @first, second
<span class="hljs-keyword">new</span> Call(floor, [div]).compileToFragments o
compileModulo: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
mod = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'modulo'</span>, o
<span class="hljs-keyword">new</span> Call(mod, [@first, @second]).compileToFragments o
toString: <span class="hljs-function"><span class="hljs-params">(idt)</span> -&gt;</span>
<span class="hljs-keyword">super</span> idt, @constructor.name + <span class="hljs-string">' '</span> + @operator</pre></div></div>
</li>
<li id="section-283">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-283">&#182;</a>
</div>
<h3 id="in">In</h3>
</div>
<div class="content"><div class='highlight'><pre>exports.In = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">In</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@object, @array)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'object'</span>, <span class="hljs-string">'array'</span>]
invert: NEGATE
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @array <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @array.isArray() <span class="hljs-keyword">and</span> @array.base.objects.length
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @array.base.objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat
hasSplat = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">break</span></pre></div></div>
</li>
<li id="section-284">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-284">&#182;</a>
</div>
<p><code>compileOrTest</code> only if we have an array literal with no splats</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> @compileOrTest o <span class="hljs-keyword">unless</span> hasSplat
@compileLoopTest o
compileOrTest: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[sub, ref] = @object.cache o, LEVEL_OP
[cmp, cnj] = <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> [<span class="hljs-string">' !== '</span>, <span class="hljs-string">' &amp;&amp; '</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">' === '</span>, <span class="hljs-string">' || '</span>]
tests = []
<span class="hljs-keyword">for</span> item, i <span class="hljs-keyword">in</span> @array.base.objects
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> tests.push @makeCode cnj
tests = tests.concat (<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> ref <span class="hljs-keyword">else</span> sub), @makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_OP <span class="hljs-keyword">then</span> tests <span class="hljs-keyword">else</span> @wrapInParentheses tests
compileLoopTest: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[sub, ref] = @object.cache o, LEVEL_LIST
fragments = [].concat @makeCode(utility(<span class="hljs-string">'indexOf'</span>, o) + <span class="hljs-string">".call("</span>), @array.compileToFragments(o, LEVEL_LIST),
@makeCode(<span class="hljs-string">", "</span>), ref, @makeCode(<span class="hljs-string">") "</span> + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'&lt; 0'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'&gt;= 0'</span>)
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> fragmentsToText(sub) <span class="hljs-keyword">is</span> fragmentsToText(ref)
fragments = sub.concat @makeCode(<span class="hljs-string">', '</span>), fragments
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments
toString: <span class="hljs-function"><span class="hljs-params">(idt)</span> -&gt;</span>
<span class="hljs-keyword">super</span> idt, @constructor.name + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span></pre></div></div>
</li>
<li id="section-285">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-285">&#182;</a>
</div>
<h3 id="try">Try</h3>
</div>
</li>
<li id="section-286">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-286">&#182;</a>
</div>
<p>A classic <em>try/catch/finally</em> block.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Try = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Try</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@attempt, @errorVariable, @recovery, @ensure)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'attempt'</span>, <span class="hljs-string">'recovery'</span>, <span class="hljs-string">'ensure'</span>]
isStatement: YES
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> @attempt.jumps(o) <span class="hljs-keyword">or</span> @recovery?.jumps(o)
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
@attempt = @attempt .makeReturn res <span class="hljs-keyword">if</span> @attempt
@recovery = @recovery.makeReturn res <span class="hljs-keyword">if</span> @recovery
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-287">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-287">&#182;</a>
</div>
<p>Compilation is more or less as you would expect the <em>finally</em> clause
is optional, the <em>catch</em> is not.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.indent += TAB
tryPart = @attempt.compileToFragments o, LEVEL_TOP
catchPart = <span class="hljs-keyword">if</span> @recovery
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">'error'</span>, reserve: <span class="hljs-literal">no</span>
placeholder = <span class="hljs-keyword">new</span> IdentifierLiteral generatedErrorVariableName
<span class="hljs-keyword">if</span> @errorVariable
message = isUnassignable @errorVariable.unwrapAll().value
@errorVariable.error message <span class="hljs-keyword">if</span> message
@recovery.unshift <span class="hljs-keyword">new</span> Assign @errorVariable, placeholder
[].concat @makeCode(<span class="hljs-string">" catch ("</span>), placeholder.compileToFragments(o), @makeCode(<span class="hljs-string">") {\n"</span>),
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
<span class="hljs-keyword">else</span> <span class="hljs-keyword">unless</span> @ensure <span class="hljs-keyword">or</span> @recovery
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">'error'</span>, reserve: <span class="hljs-literal">no</span>
[@makeCode(<span class="hljs-string">" catch (<span class="hljs-subst">#{generatedErrorVariableName}</span>) {}"</span>)]
<span class="hljs-keyword">else</span>
[]
ensurePart = <span class="hljs-keyword">if</span> @ensure <span class="hljs-keyword">then</span> ([].concat @makeCode(<span class="hljs-string">" finally {\n"</span>), @ensure.compileToFragments(o, LEVEL_TOP),
@makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)) <span class="hljs-keyword">else</span> []
[].concat @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>try {\n"</span>),
tryPart,
@makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>), catchPart, ensurePart</pre></div></div>
</li>
<li id="section-288">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-288">&#182;</a>
</div>
<h3 id="throw">Throw</h3>
</div>
</li>
<li id="section-289">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-289">&#182;</a>
</div>
<p>Simple node to throw an exception.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Throw = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Throw</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'expression'</span>]
isStatement: YES
jumps: NO</pre></div></div>
</li>
<li id="section-290">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-290">&#182;</a>
</div>
<p>A <strong>Throw</strong> is already a return, of sorts…</p>
</div>
<div class="content"><div class='highlight'><pre> makeReturn: THIS
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragments = @expression.compileToFragments o, LEVEL_LIST
unshiftAfterComments fragments, @makeCode <span class="hljs-string">'throw '</span>
fragments.unshift @makeCode @tab
fragments.push @makeCode <span class="hljs-string">';'</span>
fragments</pre></div></div>
</li>
<li id="section-291">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-291">&#182;</a>
</div>
<h3 id="existence">Existence</h3>
</div>
</li>
<li id="section-292">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-292">&#182;</a>
</div>
<p>Checks a variable for existence not <code>null</code> and not <code>undefined</code>. This is
similar to <code>.nil?</code> in Ruby, and avoids having to consult a JavaScript truth
table. Optionally only check if a variable is not <code>undefined</code>.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Existence = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Existence</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression, onlyNotUndefined = <span class="hljs-literal">no</span>)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@comparisonTarget = <span class="hljs-keyword">if</span> onlyNotUndefined <span class="hljs-keyword">then</span> <span class="hljs-string">'undefined'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'null'</span>
salvagedComments = []
@expression.traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> -&gt;</span>
<span class="hljs-keyword">if</span> child.comments
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> child.comments
salvagedComments.push comment <span class="hljs-keyword">unless</span> comment <span class="hljs-keyword">in</span> salvagedComments
<span class="hljs-keyword">delete</span> child.comments
attachCommentsToNode salvagedComments, @
moveComments @expression, @
children: [<span class="hljs-string">'expression'</span>]
invert: NEGATE
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@expression.front = @front
code = @expression.compile o, LEVEL_OP
<span class="hljs-keyword">if</span> @expression.unwrap() <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check code
[cmp, cnj] = <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> [<span class="hljs-string">'==='</span>, <span class="hljs-string">'||'</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">'!=='</span>, <span class="hljs-string">'&amp;&amp;'</span>]
code = <span class="hljs-string">"typeof <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> \"undefined\""</span> + <span class="hljs-keyword">if</span> @comparisonTarget <span class="hljs-keyword">isnt</span> <span class="hljs-string">'undefined'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">" <span class="hljs-subst">#{cnj}</span> <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> <span class="hljs-subst">#{@comparisonTarget}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-293">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-293">&#182;</a>
</div>
<p>We explicity want to use loose equality (<code>==</code>) when comparing against <code>null</code>,
so that an existence check roughly corresponds to a check for truthiness.
Do <em>not</em> change this to <code>===</code> for <code>null</code>, as this will break mountains of
existing code. When comparing only against <code>undefined</code>, however, we want to
use <code>===</code> because this use case is for parity with ES2015+ default values,
which only get assigned when the variable is <code>undefined</code> (but not <code>null</code>).</p>
</div>
<div class="content"><div class='highlight'><pre> cmp = <span class="hljs-keyword">if</span> @comparisonTarget <span class="hljs-keyword">is</span> <span class="hljs-string">'null'</span>
<span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'=='</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'!='</span>
<span class="hljs-keyword">else</span> <span class="hljs-comment"># `undefined`</span>
<span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'==='</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'!=='</span>
code = <span class="hljs-string">"<span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> <span class="hljs-subst">#{@comparisonTarget}</span>"</span>
[@makeCode(<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_COND <span class="hljs-keyword">then</span> code <span class="hljs-keyword">else</span> <span class="hljs-string">"(<span class="hljs-subst">#{code}</span>)"</span>)]</pre></div></div>
</li>
<li id="section-294">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-294">&#182;</a>
</div>
<h3 id="parens">Parens</h3>
</div>
</li>
<li id="section-295">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-295">&#182;</a>
</div>
<p>An extra set of parentheses, specified explicitly in the source. At one time
we tried to clean up the results by detecting and removing redundant
parentheses, but no longer you can put in as many as you please.</p>
<p>Parentheses are a good way to force any statement to become an expression.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Parens = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parens</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'body'</span>]
unwrap: <span class="hljs-function">-&gt;</span> @body
shouldCache: <span class="hljs-function">-&gt;</span> @body.shouldCache()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
expr = @body.unwrap()</pre></div></div>
</li>
<li id="section-296">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-296">&#182;</a>
</div>
<p>If these parentheses are wrapping an <code>IdentifierLiteral</code> followed by a
block comment, output the parentheses (or put another way, dont optimize
away these redundant parentheses). This is because Flow requires
parentheses in certain circumstances to distinguish identifiers followed
by comment-based type annotations from JavaScript labels.</p>
</div>
<div class="content"><div class='highlight'><pre> shouldWrapComment = expr.comments?.some(
<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.unshift <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.newLine)
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isAtomic() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @csxAttribute <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> shouldWrapComment
expr.front = @front
<span class="hljs-keyword">return</span> expr.compileToFragments o
fragments = expr.compileToFragments o, LEVEL_PAREN
bare = o.level &lt; LEVEL_OP <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> shouldWrapComment <span class="hljs-keyword">and</span> (
expr <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">or</span> expr.unwrap() <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">or</span>
(expr <span class="hljs-keyword">instanceof</span> For <span class="hljs-keyword">and</span> expr.returns)
) <span class="hljs-keyword">and</span> (o.level &lt; LEVEL_COND <span class="hljs-keyword">or</span> fragments.length &lt;= <span class="hljs-number">3</span>)
<span class="hljs-keyword">return</span> @wrapInBraces fragments <span class="hljs-keyword">if</span> @csxAttribute
<span class="hljs-keyword">if</span> bare <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments</pre></div></div>
</li>
<li id="section-297">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-297">&#182;</a>
</div>
<h3 id="stringwithinterpolations">StringWithInterpolations</h3>
</div>
<div class="content"><div class='highlight'><pre>
exports.StringWithInterpolations = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringWithInterpolations</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'body'</span>]</pre></div></div>
</li>
<li id="section-298">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-298">&#182;</a>
</div>
<p><code>unwrap</code> returns <code>this</code> to stop ancestor nodes reaching in to grab @body,
and using @body.compileNode. <code>StringWithInterpolations.compileNode</code> is
<em>the</em> custom logic to output interpolated strings as code.</p>
</div>
<div class="content"><div class='highlight'><pre> unwrap: <span class="hljs-function">-&gt;</span> <span class="hljs-keyword">this</span>
shouldCache: <span class="hljs-function">-&gt;</span> @body.shouldCache()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @csxAttribute
wrapped = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> StringWithInterpolations @body
wrapped.csxAttribute = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span> wrapped.compileNode o</pre></div></div>
</li>
<li id="section-299">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-299">&#182;</a>
</div>
<p>Assumes that <code>expr</code> is <code>Value</code> » <code>StringLiteral</code> or <code>Op</code></p>
</div>
<div class="content"><div class='highlight'><pre> expr = @body.unwrap()
elements = []
salvagedComments = []
expr.traverseChildren <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">if</span> node.comments
salvagedComments.push node.comments...
<span class="hljs-keyword">delete</span> node.comments
elements.push node
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Parens
<span class="hljs-keyword">if</span> salvagedComments.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> salvagedComments
comment.unshift = <span class="hljs-literal">yes</span>
comment.newLine = <span class="hljs-literal">yes</span>
attachCommentsToNode salvagedComments, node
elements.push node
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.comments</pre></div></div>
</li>
<li id="section-300">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-300">&#182;</a>
</div>
<p>This node is getting discarded, but salvage its comments.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> elements.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> elements[elements.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
comment.unshift = <span class="hljs-literal">no</span>
comment.newLine = <span class="hljs-literal">yes</span>
attachCommentsToNode node.comments, elements[elements.length - <span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>
salvagedComments.push node.comments...
<span class="hljs-keyword">delete</span> node.comments
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
fragments = []
fragments.push @makeCode <span class="hljs-string">'`'</span> <span class="hljs-keyword">unless</span> @csx
<span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> elements
<span class="hljs-keyword">if</span> element <span class="hljs-keyword">instanceof</span> StringLiteral
element.value = element.unquote <span class="hljs-literal">yes</span>, @csx
<span class="hljs-keyword">unless</span> @csx</pre></div></div>
</li>
<li id="section-301">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-301">&#182;</a>
</div>
<p>Backticks and <code>${</code> inside template literals must be escaped.</p>
</div>
<div class="content"><div class='highlight'><pre> element.value = element.value.replace <span class="hljs-regexp">/(\\*)(`|\$\{)/g</span>, <span class="hljs-function"><span class="hljs-params">(match, backslashes, toBeEscaped)</span> -&gt;</span>
<span class="hljs-keyword">if</span> backslashes.length % <span class="hljs-number">2</span> <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-string">"<span class="hljs-subst">#{backslashes}</span>\\<span class="hljs-subst">#{toBeEscaped}</span>"</span>
<span class="hljs-keyword">else</span>
match
fragments.push element.compileToFragments(o)...
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">'$'</span> <span class="hljs-keyword">unless</span> @csx
code = element.compileToFragments(o, LEVEL_PAREN)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @isNestedTag(element) <span class="hljs-keyword">or</span> code.some(<span class="hljs-function"><span class="hljs-params">(fragment)</span> -&gt;</span> fragment.comments?)
code = @wrapInBraces code</pre></div></div>
</li>
<li id="section-302">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-302">&#182;</a>
</div>
<p>Flag the <code>{</code> and <code>}</code> fragments as having been generated by this
<code>StringWithInterpolations</code> node, so that <code>compileComments</code> knows
to treat them as bounds. Dont trust <code>fragment.type</code>, which can
report minified variable names when this compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> code[<span class="hljs-number">0</span>].isStringWithInterpolations = <span class="hljs-literal">yes</span>
code[code.length - <span class="hljs-number">1</span>].isStringWithInterpolations = <span class="hljs-literal">yes</span>
fragments.push code...
fragments.push @makeCode <span class="hljs-string">'`'</span> <span class="hljs-keyword">unless</span> @csx
fragments
isNestedTag: <span class="hljs-function"><span class="hljs-params">(element)</span> -&gt;</span>
exprs = element.body?.expressions
call = exprs?[<span class="hljs-number">0</span>].unwrap()
@csx <span class="hljs-keyword">and</span> exprs <span class="hljs-keyword">and</span> exprs.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> call <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> call.csx</pre></div></div>
</li>
<li id="section-303">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-303">&#182;</a>
</div>
<h3 id="for">For</h3>
</div>
</li>
<li id="section-304">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-304">&#182;</a>
</div>
<p>CoffeeScripts replacement for the <em>for</em> loop is our array and object
comprehensions, that compile into <em>for</em> loops here. They also act as an
expression, able to return the result of each filtered iteration.</p>
<p>Unlike Python array comprehensions, they can be multi-line, and you can pass
the current index of the loop as a second parameter. Unlike Ruby blocks,
you can map and filter in a single pass.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.For = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">For</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">While</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(body, source)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
{@source, @guard, @step, @name, @index} = source
@body = Block.wrap [body]
@own = source.own?
@object = source.object?
@from = source.<span class="hljs-keyword">from</span>?
@index.error <span class="hljs-string">'cannot use index with for-from'</span> <span class="hljs-keyword">if</span> @from <span class="hljs-keyword">and</span> @index
source.ownTag.error <span class="hljs-string">"cannot use own with for-<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @from <span class="hljs-keyword">then</span> <span class="hljs-string">'from'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'in'</span>}</span>"</span> <span class="hljs-keyword">if</span> @own <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @object
[@name, @index] = [@index, @name] <span class="hljs-keyword">if</span> @object
@index.error <span class="hljs-string">'index cannot be a pattern matching expression'</span> <span class="hljs-keyword">if</span> @index?.isArray?() <span class="hljs-keyword">or</span> @index?.isObject?()
@range = @source <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @source.base <span class="hljs-keyword">instanceof</span> Range <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @source.properties.length <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @from
@pattern = @name <span class="hljs-keyword">instanceof</span> Value
@index.error <span class="hljs-string">'indexes do not apply to range loops'</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @index
@name.error <span class="hljs-string">'cannot pattern match over range loops'</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @pattern
@returns = <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-305">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-305">&#182;</a>
</div>
<p>Move up any comments in the “<code>for</code> line”, i.e. the line of code with <code>for</code>,
from any child nodes of that line up to the <code>for</code> node itself so that these
comments get output, and get output above the <code>for</code> loop.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> attribute <span class="hljs-keyword">in</span> [<span class="hljs-string">'source'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'step'</span>, <span class="hljs-string">'name'</span>, <span class="hljs-string">'index'</span>] <span class="hljs-keyword">when</span> @[attribute]
@[attribute].traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node.comments</pre></div></div>
</li>
<li id="section-306">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-306">&#182;</a>
</div>
<p>These comments are buried pretty deeply, so if they happen to be
trailing comments the line they trail will be unrecognizable when
were done compiling this <code>for</code> loop; so just shift them up to
output above the <code>for</code> line.</p>
</div>
<div class="content"><div class='highlight'><pre> comment.newLine = comment.unshift = <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
moveComments node, @[attribute]
moveComments @[attribute], @
children: [<span class="hljs-string">'body'</span>, <span class="hljs-string">'source'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'step'</span>]</pre></div></div>
</li>
<li id="section-307">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-307">&#182;</a>
</div>
<p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
loop, filtering, stepping, and result saving for array, object, and range
comprehensions. Some of the generated code can be shared in common, and
some cannot.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
body = Block.wrap [@body]
[..., last] = body.expressions
@returns = <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> last?.jumps() <span class="hljs-keyword">instanceof</span> Return
source = <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">then</span> @source.base <span class="hljs-keyword">else</span> @source
scope = o.scope
name = @name <span class="hljs-keyword">and</span> (@name.compile o, LEVEL_LIST) <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @pattern
index = @index <span class="hljs-keyword">and</span> (@index.compile o, LEVEL_LIST)
scope.find(name) <span class="hljs-keyword">if</span> name <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @pattern
scope.find(index) <span class="hljs-keyword">if</span> index <span class="hljs-keyword">and</span> @index <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Value
rvar = scope.freeVariable <span class="hljs-string">'results'</span> <span class="hljs-keyword">if</span> @returns
<span class="hljs-keyword">if</span> @from
ivar = scope.freeVariable <span class="hljs-string">'x'</span>, single: <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> @pattern
<span class="hljs-keyword">else</span>
ivar = (@object <span class="hljs-keyword">and</span> index) <span class="hljs-keyword">or</span> scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
kvar = ((@range <span class="hljs-keyword">or</span> @from) <span class="hljs-keyword">and</span> name) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">or</span> ivar
kvarAssign = <span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> = "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
<span class="hljs-keyword">if</span> @step <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @range
[step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST, shouldCacheOrIsAssignable
stepNum = Number stepVar <span class="hljs-keyword">if</span> @step.isNumber()
name = ivar <span class="hljs-keyword">if</span> @pattern
varPart = <span class="hljs-string">''</span>
guardPart = <span class="hljs-string">''</span>
defPart = <span class="hljs-string">''</span>
idt1 = @tab + TAB
<span class="hljs-keyword">if</span> @range
forPartFragments = source.compileToFragments merge o,
{index: ivar, name, @step, shouldCache: shouldCacheOrIsAssignable}
<span class="hljs-keyword">else</span>
svar = @source.compile o, LEVEL_LIST
<span class="hljs-keyword">if</span> (name <span class="hljs-keyword">or</span> @own) <span class="hljs-keyword">and</span> @source.unwrap() <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> IdentifierLiteral
defPart += <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{ref = scope.freeVariable <span class="hljs-string">'ref'</span>}</span> = <span class="hljs-subst">#{svar}</span>;\n"</span>
svar = ref
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @pattern <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @from
namePart = <span class="hljs-string">"<span class="hljs-subst">#{name}</span> = <span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @object <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @from
defPart += <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{step}</span>;\n"</span> <span class="hljs-keyword">if</span> step <span class="hljs-keyword">isnt</span> stepVar
down = stepNum &lt; <span class="hljs-number">0</span>
lvar = scope.freeVariable <span class="hljs-string">'len'</span> <span class="hljs-keyword">unless</span> @step <span class="hljs-keyword">and</span> stepNum? <span class="hljs-keyword">and</span> down
declare = <span class="hljs-string">"<span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{ivar}</span> = 0, <span class="hljs-subst">#{lvar}</span> = <span class="hljs-subst">#{svar}</span>.length"</span>
declareDown = <span class="hljs-string">"<span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{svar}</span>.length - 1"</span>
compare = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> &lt; <span class="hljs-subst">#{lvar}</span>"</span>
compareDown = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> &gt;= 0"</span>
<span class="hljs-keyword">if</span> @step
<span class="hljs-keyword">if</span> stepNum?
<span class="hljs-keyword">if</span> down
compare = compareDown
declare = declareDown
<span class="hljs-keyword">else</span>
compare = <span class="hljs-string">"<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? <span class="hljs-subst">#{compare}</span> : <span class="hljs-subst">#{compareDown}</span>"</span>
declare = <span class="hljs-string">"(<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? (<span class="hljs-subst">#{declare}</span>) : <span class="hljs-subst">#{declareDown}</span>)"</span>
increment = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> += <span class="hljs-subst">#{stepVar}</span>"</span>
<span class="hljs-keyword">else</span>
increment = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"++<span class="hljs-subst">#{ivar}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>}</span>"</span>
forPartFragments = [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{declare}</span>; <span class="hljs-subst">#{compare}</span>; <span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{increment}</span>"</span>)]
<span class="hljs-keyword">if</span> @returns
resultPart = <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span>
returnResult = <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;"</span>
body.makeReturn rvar
<span class="hljs-keyword">if</span> @guard
<span class="hljs-keyword">if</span> body.expressions.length &gt; <span class="hljs-number">1</span>
body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens @guard).invert(), <span class="hljs-keyword">new</span> StatementLiteral <span class="hljs-string">"continue"</span>
<span class="hljs-keyword">else</span>
body = Block.wrap [<span class="hljs-keyword">new</span> If @guard, body] <span class="hljs-keyword">if</span> @guard
<span class="hljs-keyword">if</span> @pattern
body.expressions.unshift <span class="hljs-keyword">new</span> Assign @name, <span class="hljs-keyword">if</span> @from <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> IdentifierLiteral kvar <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span>
varPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span><span class="hljs-subst">#{namePart}</span>;"</span> <span class="hljs-keyword">if</span> namePart
<span class="hljs-keyword">if</span> @object
forPartFragments = [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> in <span class="hljs-subst">#{svar}</span>"</span>)]
guardPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span>if (!<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(<span class="hljs-subst">#{svar}</span>, <span class="hljs-subst">#{kvar}</span>)) continue;"</span> <span class="hljs-keyword">if</span> @own
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @from
forPartFragments = [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> of <span class="hljs-subst">#{svar}</span>"</span>)]
bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
<span class="hljs-keyword">if</span> bodyFragments <span class="hljs-keyword">and</span> bodyFragments.length &gt; <span class="hljs-number">0</span>
bodyFragments = [].concat @makeCode(<span class="hljs-string">'\n'</span>), bodyFragments, @makeCode(<span class="hljs-string">'\n'</span>)
fragments = [@makeCode(defPart)]
fragments.push @makeCode(resultPart) <span class="hljs-keyword">if</span> resultPart
fragments = fragments.concat @makeCode(@tab), @makeCode( <span class="hljs-string">'for ('</span>),
forPartFragments, @makeCode(<span class="hljs-string">") {<span class="hljs-subst">#{guardPart}</span><span class="hljs-subst">#{varPart}</span>"</span>), bodyFragments,
@makeCode(@tab), @makeCode(<span class="hljs-string">'}'</span>)
fragments.push @makeCode(returnResult) <span class="hljs-keyword">if</span> returnResult
fragments</pre></div></div>
</li>
<li id="section-308">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-308">&#182;</a>
</div>
<h3 id="switch">Switch</h3>
</div>
</li>
<li id="section-309">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-309">&#182;</a>
</div>
<p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Switch = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Switch</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@subject, @cases, @otherwise)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
children: [<span class="hljs-string">'subject'</span>, <span class="hljs-string">'cases'</span>, <span class="hljs-string">'otherwise'</span>]
isStatement: YES
jumps: <span class="hljs-function"><span class="hljs-params">(o = {block: <span class="hljs-literal">yes</span>})</span> -&gt;</span>
<span class="hljs-keyword">for</span> [conds, block] <span class="hljs-keyword">in</span> @cases
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = block.jumps o
@otherwise?.jumps o
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
pair[<span class="hljs-number">1</span>].makeReturn res <span class="hljs-keyword">for</span> pair <span class="hljs-keyword">in</span> @cases
@otherwise <span class="hljs-keyword">or</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'void 0'</span>] <span class="hljs-keyword">if</span> res
@otherwise?.makeReturn res
<span class="hljs-keyword">this</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
idt1 = o.indent + TAB
idt2 = o.indent = idt1 + TAB
fragments = [].concat @makeCode(@tab + <span class="hljs-string">"switch ("</span>),
(<span class="hljs-keyword">if</span> @subject <span class="hljs-keyword">then</span> @subject.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">else</span> @makeCode <span class="hljs-string">"false"</span>),
@makeCode(<span class="hljs-string">") {\n"</span>)
<span class="hljs-keyword">for</span> [conditions, block], i <span class="hljs-keyword">in</span> @cases
<span class="hljs-keyword">for</span> cond <span class="hljs-keyword">in</span> flatten [conditions]
cond = cond.invert() <span class="hljs-keyword">unless</span> @subject
fragments = fragments.concat @makeCode(idt1 + <span class="hljs-string">"case "</span>), cond.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">":\n"</span>)
fragments = fragments.concat body, @makeCode(<span class="hljs-string">'\n'</span>) <span class="hljs-keyword">if</span> (body = block.compileToFragments o, LEVEL_TOP).length &gt; <span class="hljs-number">0</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> @cases.length - <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @otherwise
expr = @lastNode block.expressions
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">or</span> expr <span class="hljs-keyword">instanceof</span> Throw <span class="hljs-keyword">or</span> (expr <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> expr.jumps() <span class="hljs-keyword">and</span> expr.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'debugger'</span>)
fragments.push cond.makeCode(idt2 + <span class="hljs-string">'break;\n'</span>)
<span class="hljs-keyword">if</span> @otherwise <span class="hljs-keyword">and</span> @otherwise.expressions.length
fragments.push @makeCode(idt1 + <span class="hljs-string">"default:\n"</span>), (@otherwise.compileToFragments o, LEVEL_TOP)..., @makeCode(<span class="hljs-string">"\n"</span>)
fragments.push @makeCode @tab + <span class="hljs-string">'}'</span>
fragments</pre></div></div>
</li>
<li id="section-310">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-310">&#182;</a>
</div>
<h3 id="if">If</h3>
</div>
</li>
<li id="section-311">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-311">&#182;</a>
</div>
<p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
to the last line of each clause.</p>
<p>Single-expression <strong>Ifs</strong> are compiled into conditional operators if possible,
because ternaries are already proper expressions, and dont need conversion.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.If = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">If</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(condition, @body, options = {})</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
@condition = <span class="hljs-keyword">if</span> options.type <span class="hljs-keyword">is</span> <span class="hljs-string">'unless'</span> <span class="hljs-keyword">then</span> condition.invert() <span class="hljs-keyword">else</span> condition
@elseBody = <span class="hljs-literal">null</span>
@isChain = <span class="hljs-literal">false</span>
{@soak} = options
moveComments @condition, @ <span class="hljs-keyword">if</span> @condition.comments
children: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'body'</span>, <span class="hljs-string">'elseBody'</span>]
bodyNode: <span class="hljs-function">-&gt;</span> @body?.unwrap()
elseBodyNode: <span class="hljs-function">-&gt;</span> @elseBody?.unwrap()</pre></div></div>
</li>
<li id="section-312">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-312">&#182;</a>
</div>
<p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p>
</div>
<div class="content"><div class='highlight'><pre> addElse: <span class="hljs-function"><span class="hljs-params">(elseBody)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @isChain
@elseBodyNode().addElse elseBody
<span class="hljs-keyword">else</span>
@isChain = elseBody <span class="hljs-keyword">instanceof</span> If
@elseBody = @ensureBlock elseBody
@elseBody.updateLocationDataIfMissing elseBody.locationData
<span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-313">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-313">&#182;</a>
</div>
<p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
to be a statement. Otherwise a conditional operator is safe.</p>
</div>
<div class="content"><div class='highlight'><pre> isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span>
@bodyNode().isStatement(o) <span class="hljs-keyword">or</span> @elseBodyNode()?.isStatement(o)
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> @body.jumps(o) <span class="hljs-keyword">or</span> @elseBody?.jumps(o)
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @isStatement o <span class="hljs-keyword">then</span> @compileStatement o <span class="hljs-keyword">else</span> @compileExpression o
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
@elseBody <span class="hljs-keyword">or</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'void 0'</span>] <span class="hljs-keyword">if</span> res
@body <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@body.makeReturn res]
@elseBody <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@elseBody.makeReturn res]
<span class="hljs-keyword">this</span>
ensureBlock: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Block <span class="hljs-keyword">then</span> node <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Block [node]</pre></div></div>
</li>
<li id="section-314">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-314">&#182;</a>
</div>
<p>Compile the <code>If</code> as a regular <em>if-else</em> statement. Flattened chains
force inner <em>else</em> bodies into statement form.</p>
</div>
<div class="content"><div class='highlight'><pre> compileStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
child = del o, <span class="hljs-string">'chainChild'</span>
exeq = del o, <span class="hljs-string">'isExistentialEquals'</span>
<span class="hljs-keyword">if</span> exeq
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If(@condition.invert(), @elseBodyNode(), type: <span class="hljs-string">'if'</span>).compileToFragments o
indent = o.indent + TAB
cond = @condition.compileToFragments o, LEVEL_PAREN
body = @ensureBlock(@body).compileToFragments merge o, {indent}
ifPart = [].concat @makeCode(<span class="hljs-string">"if ("</span>), cond, @makeCode(<span class="hljs-string">") {\n"</span>), body, @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
ifPart.unshift @makeCode @tab <span class="hljs-keyword">unless</span> child
<span class="hljs-keyword">return</span> ifPart <span class="hljs-keyword">unless</span> @elseBody
answer = ifPart.concat @makeCode(<span class="hljs-string">' else '</span>)
<span class="hljs-keyword">if</span> @isChain
o.chainChild = <span class="hljs-literal">yes</span>
answer = answer.concat @elseBody.unwrap().compileToFragments o, LEVEL_TOP
<span class="hljs-keyword">else</span>
answer = answer.concat @makeCode(<span class="hljs-string">"{\n"</span>), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
answer</pre></div></div>
</li>
<li id="section-315">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-315">&#182;</a>
</div>
<p>Compile the <code>If</code> as a conditional operator.</p>
</div>
<div class="content"><div class='highlight'><pre> compileExpression: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
cond = @condition.compileToFragments o, LEVEL_COND
body = @bodyNode().compileToFragments o, LEVEL_LIST
alt = <span class="hljs-keyword">if</span> @elseBodyNode() <span class="hljs-keyword">then</span> @elseBodyNode().compileToFragments(o, LEVEL_LIST) <span class="hljs-keyword">else</span> [@makeCode(<span class="hljs-string">'void 0'</span>)]
fragments = cond.concat @makeCode(<span class="hljs-string">" ? "</span>), body, @makeCode(<span class="hljs-string">" : "</span>), alt
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_COND <span class="hljs-keyword">then</span> @wrapInParentheses fragments <span class="hljs-keyword">else</span> fragments
unfoldSoak: <span class="hljs-function">-&gt;</span>
@soak <span class="hljs-keyword">and</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
<li id="section-316">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-316">&#182;</a>
</div>
<h2 id="constants">Constants</h2>
</div>
</li>
<li id="section-317">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-317">&#182;</a>
</div>
</div>
<div class="content"><div class='highlight'><pre>
UTILITIES =
modulo: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'function(a, b) { return (+a % (b = +b) + b) % b; }'</span>
objectWithoutKeys: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"
function(o, ks) {
var res = {};
for (var k in o) ([].indexOf.call(ks, k) &lt; 0 &amp;&amp; {}.hasOwnProperty.call(o, k)) &amp;&amp; (res[k] = o[k]);
return res;
}
"</span>
boundMethodCheck: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"
function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new Error('Bound instance method accessed before binding');
}
}
"</span>
_extends: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"
Object.assign || function (target) {
for (var i = 1; i &lt; arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
}
"</span></pre></div></div>
</li>
<li id="section-318">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-318">&#182;</a>
</div>
<p>Shortcuts to speed up the lookup time for native functions.</p>
</div>
<div class="content"><div class='highlight'><pre> hasProp: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'{}.hasOwnProperty'</span>
indexOf: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'[].indexOf'</span>
slice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">'[].slice'</span>
splice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">'[].splice'</span></pre></div></div>
</li>
<li id="section-319">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-319">&#182;</a>
</div>
<p>Levels indicate a nodes position in the AST. Useful for knowing if
parens are necessary or superfluous.</p>
</div>
<div class="content"><div class='highlight'><pre>LEVEL_TOP = <span class="hljs-number">1</span> <span class="hljs-comment"># ...;</span>
LEVEL_PAREN = <span class="hljs-number">2</span> <span class="hljs-comment"># (...)</span>
LEVEL_LIST = <span class="hljs-number">3</span> <span class="hljs-comment"># [...]</span>
LEVEL_COND = <span class="hljs-number">4</span> <span class="hljs-comment"># ... ? x : y</span>
LEVEL_OP = <span class="hljs-number">5</span> <span class="hljs-comment"># !...</span>
LEVEL_ACCESS = <span class="hljs-number">6</span> <span class="hljs-comment"># ...[0]</span></pre></div></div>
</li>
<li id="section-320">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-320">&#182;</a>
</div>
<p>Tabs are two spaces for pretty printing.</p>
</div>
<div class="content"><div class='highlight'><pre>TAB = <span class="hljs-string">' '</span>
SIMPLENUM = <span class="hljs-regexp">/^[+-]?\d+$/</span></pre></div></div>
</li>
<li id="section-321">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-321">&#182;</a>
</div>
<h2 id="helper-functions">Helper Functions</h2>
</div>
</li>
<li id="section-322">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-322">&#182;</a>
</div>
</div>
</li>
<li id="section-323">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-323">&#182;</a>
</div>
<p>Helper for ensuring that utility functions are assigned at the top level.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">utility</span> = <span class="hljs-params">(name, o)</span> -&gt;</span>
{root} = o.scope
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">of</span> root.utilities
root.utilities[name]
<span class="hljs-keyword">else</span>
ref = root.freeVariable name
root.assign ref, UTILITIES[name] o
root.utilities[name] = ref
<span class="hljs-function">
<span class="hljs-title">multident</span> = <span class="hljs-params">(code, tab, includingFirstLine = <span class="hljs-literal">yes</span>)</span> -&gt;</span>
endsWithNewLine = code[code.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'\n'</span>
code = (<span class="hljs-keyword">if</span> includingFirstLine <span class="hljs-keyword">then</span> tab <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>) + code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">"$&amp;<span class="hljs-subst">#{tab}</span>"</span>
code = code.replace <span class="hljs-regexp">/\s+$/</span>, <span class="hljs-string">''</span>
code = code + <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> endsWithNewLine
code</pre></div></div>
</li>
<li id="section-324">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-324">&#182;</a>
</div>
<p>Wherever in CoffeeScript 1 we mightve inserted a <code>makeCode &quot;#{@tab}&quot;</code> to
indent a line of code, now we must account for the possibility of comments
preceding that line of code. If there are such comments, indent each line of
such comments, and <em>then</em> indent the first following line of code.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">indentInitial</span> = <span class="hljs-params">(fragments, node)</span> -&gt;</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = multident fragment.code, node.tab
<span class="hljs-keyword">else</span>
fragments.splice fragmentIndex, <span class="hljs-number">0</span>, node.makeCode <span class="hljs-string">"<span class="hljs-subst">#{node.tab}</span>"</span>
<span class="hljs-keyword">break</span>
fragments
<span class="hljs-function">
<span class="hljs-title">hasLineComments</span> = <span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node.comments
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> comment.here <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-325">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-325">&#182;</a>
</div>
<p>Move the <code>comments</code> property from one object to another, deleting it from
the first object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">moveComments</span> = <span class="hljs-params">(<span class="hljs-keyword">from</span>, to)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> <span class="hljs-keyword">from</span>?.comments
attachCommentsToNode <span class="hljs-keyword">from</span>.comments, to
<span class="hljs-keyword">delete</span> <span class="hljs-keyword">from</span>.comments</pre></div></div>
</li>
<li id="section-326">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-326">&#182;</a>
</div>
<p>Sometimes when compiling a node, we want to insert a fragment at the start
of an array of fragments; but if the start has one or more comment fragments,
we want to insert this fragment after those but before any non-comments.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">unshiftAfterComments</span> = <span class="hljs-params">(fragments, fragmentToInsert)</span> -&gt;</span>
inserted = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> fragment.isComment
fragments.splice fragmentIndex, <span class="hljs-number">0</span>, fragmentToInsert
inserted = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">break</span>
fragments.push fragmentToInsert <span class="hljs-keyword">unless</span> inserted
fragments
<span class="hljs-function">
<span class="hljs-title">isLiteralArguments</span> = <span class="hljs-params">(node)</span> -&gt;</span>
node <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">is</span> <span class="hljs-string">'arguments'</span>
<span class="hljs-function">
<span class="hljs-title">isLiteralThis</span> = <span class="hljs-params">(node)</span> -&gt;</span>
node <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">or</span> (node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound)
<span class="hljs-function">
<span class="hljs-title">shouldCacheOrIsAssignable</span> = <span class="hljs-params">(node)</span> -&gt;</span> node.shouldCache() <span class="hljs-keyword">or</span> node.isAssignable?()</pre></div></div>
</li>
<li id="section-327">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-327">&#182;</a>
</div>
<p>Unfold a nodes child if soak, then tuck the node under created <code>If</code></p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">unfoldSoak</span> = <span class="hljs-params">(o, parent, name)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> ifn = parent[name].unfoldSoak o
parent[name] = ifn.body
ifn.body = <span class="hljs-keyword">new</span> Value parent
ifn</pre></div></div>
</li>
</ul>
</div>
</body>
</html>