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
2017-04-13 20:37:55 -07:00

6245 lines
335 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,
addLocationDataFn, 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.addLocationDataFn = addLocationDataFn</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>
@locationData = parent?.locationData
@type = parent?.constructor?.name <span class="hljs-keyword">or</span> <span class="hljs-string">'unknown'</span>
toString: <span class="hljs-function">-&gt;</span>
<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-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#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-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<h3 id="base">Base</h3>
</div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#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-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#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
<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</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#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</pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#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-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#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-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#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-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#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-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>Pull out the last non-comment node of a node list.</p>
</div>
<div class="content"><div class='highlight'><pre> lastNonComment: <span class="hljs-function"><span class="hljs-params">(list)</span> -&gt;</span>
i = list.length
<span class="hljs-keyword">return</span> list[i] <span class="hljs-keyword">while</span> i-- <span class="hljs-keyword">when</span> list[i] <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
<span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#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-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#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-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#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-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#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-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#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-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#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-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#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-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#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-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#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-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#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
@locationData = locationData
@eachChild (child) -&gt;
child.updateLocationDataIfMissing locationData</pre></div></div>
</li>
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">&#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>
[].concat @makeCode(<span class="hljs-string">'('</span>), fragments, @makeCode(<span class="hljs-string">')'</span>)</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>fragmentsList</code> is an array of arrays of fragments. Each array in fragmentsList will be
concatonated 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-29">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-29">&#182;</a>
</div>
<h3 id="hoisttarget">HoistTarget</h3>
</div>
</li>
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#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-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-31">&#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-32">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-32">&#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-33">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-33">&#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-34">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-34">&#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-35">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-35">&#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-36">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-36">&#182;</a>
</div>
<h3 id="block">Block</h3>
</div>
</li>
<li id="section-37">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-37">&#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-38">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-38">&#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-39">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-39">&#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-40">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-40">&#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-41">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-41">&#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-42">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-42">&#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-43">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-43">&#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]
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
@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-44">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-44">&#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-45">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-45">&#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
node = node.unwrapAll()
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-46">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-46">&#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> node.hoisted</pre></div></div>
</li>
<li id="section-47">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-47">&#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">else</span> <span class="hljs-keyword">if</span> top
node.front = <span class="hljs-literal">true</span>
fragments = node.compileToFragments o
<span class="hljs-keyword">unless</span> node.isStatement o
fragments.unshift @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>"</span>
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-48">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-48">&#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-49">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-49">&#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> []
prelude = []
<span class="hljs-keyword">unless</span> o.bare
preludeExps = <span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> @expressions
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp.unwrap() <span class="hljs-keyword">instanceof</span> Comment
exp
rest = @expressions[preludeExps.length...]
@expressions = preludeExps
<span class="hljs-keyword">if</span> preludeExps.length
prelude = @compileNode merge(o, indent: <span class="hljs-string">''</span>)
prelude.push @makeCode <span class="hljs-string">"\n"</span>
@expressions = rest
fragments = @compileWithDeclarations o
HoistTarget.expand fragments
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> o.bare
[].concat prelude, @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-50">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-50">&#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> Comment <span class="hljs-keyword">or</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
fragments.push @makeCode scope.declaredVariables().join(<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</pre></div></div>
</li>
<li id="section-51">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-51">&#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-52">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-52">&#182;</a>
</div>
<h3 id="literal">Literal</h3>
</div>
</li>
<li id="section-53">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-53">&#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>
<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>
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.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.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-54">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-54">&#182;</a>
</div>
<h3 id="return">Return</h3>
</div>
</li>
<li id="section-55">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-55">&#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-56">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-56">&#182;</a>
</div>
<p>TODO: If we call expression.compile() here twice, well sometimes get back different results!</p>
</div>
<div class="content"><div class='highlight'><pre> answer.push @makeCode @tab + <span class="hljs-string">"return<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @expression <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">if</span> @expression
answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
answer.push @makeCode <span class="hljs-string">";"</span>
<span class="hljs-keyword">return</span> answer</pre></div></div>
</li>
<li id="section-57">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-57">&#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-58">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-58">&#182;</a>
</div>
<h3 id="value">Value</h3>
</div>
</li>
<li id="section-59">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-59">&#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">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
<span class="hljs-keyword">super</span>()
@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
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
children: [<span class="hljs-string">'base'</span>, <span class="hljs-string">'properties'</span>]</pre></div></div>
</li>
<li id="section-60">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-60">&#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
<span class="hljs-keyword">this</span>
hasProperties: <span class="hljs-function">-&gt;</span>
!!@properties.length
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-61">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-61">&#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)
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-62">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-62">&#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-63">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-63">&#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-64">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-64">&#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
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-65">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-65">&#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;
<span class="hljs-keyword">if</span> ifn = @base.unfoldSoak o
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-66">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-66">&#182;</a>
</div>
<h3 id="comment">Comment</h3>
</div>
</li>
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-67">&#182;</a>
</div>
<p>CoffeeScript passes through block comments as JavaScript block comments
at the same position.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Comment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@comment)</span> -&gt;</span>
<span class="hljs-keyword">super</span>()
isStatement: YES
makeReturn: THIS
compileNode: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
comment = @comment.replace <span class="hljs-regexp">/^(\s*)#(?=\s)/gm</span>, <span class="hljs-string">"$1 *"</span>
code = <span class="hljs-string">"/*<span class="hljs-subst">#{multident comment, @tab}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> comment <span class="hljs-keyword">then</span> <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span> */"</span>
code = o.indent + code <span class="hljs-keyword">if</span> (level <span class="hljs-keyword">or</span> o.level) <span class="hljs-keyword">is</span> LEVEL_TOP
[@makeCode(<span class="hljs-string">"\n"</span>), @makeCode(code)]</pre></div></div>
</li>
<li id="section-68">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-68">&#182;</a>
</div>
<h3 id="call">Call</h3>
</div>
</li>
<li id="section-69">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-69">&#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)</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>
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'args'</span>]</pre></div></div>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">&#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-71">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-71">&#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-72">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-72">&#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-73">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-73">&#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>
@variable?.front = @front
compiledArgs = []
<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</pre></div></div>
</li>
<li id="section-74">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-74">&#182;</a>
</div>
<h3 id="super">Super</h3>
</div>
</li>
<li id="section-75">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-75">&#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-76">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-76">&#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>
children: [<span class="hljs-string">'accessor'</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@accessor)</span> -&gt;</span>
<span class="hljs-keyword">super</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
@inCtor = !!method.ctor
<span class="hljs-keyword">unless</span> @inCtor <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">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</pre></div></div>
</li>
<li id="section-77">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-77">&#182;</a>
</div>
<h3 id="regexwithinterpolations">RegexWithInterpolations</h3>
</div>
</li>
<li id="section-78">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-78">&#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-79">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-79">&#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-80">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-80">&#182;</a>
</div>
<h3 id="extends">Extends</h3>
</div>
</li>
<li id="section-81">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-81">&#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-82">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-82">&#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-83">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-83">&#182;</a>
</div>
<h3 id="access">Access</h3>
</div>
</li>
<li id="section-84">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-84">&#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
<span class="hljs-keyword">if</span> node.value <span class="hljs-keyword">in</span> JS_FORBIDDEN
[@makeCode(<span class="hljs-string">'["'</span>), name..., @makeCode(<span class="hljs-string">'"]'</span>)]
<span class="hljs-keyword">else</span>
[@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-85">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-85">&#182;</a>
</div>
<h3 id="index">Index</h3>
</div>
</li>
<li id="section-86">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-86">&#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-87">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-87">&#182;</a>
</div>
<h3 id="range">Range</h3>
</div>
</li>
<li id="section-88">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-88">&#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-89">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-89">&#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-90">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-90">&#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-91">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-91">&#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-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-92">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-92">&#182;</a>
</div>
<p>Generate the condition.</p>
</div>
<div class="content"><div class='highlight'><pre> condPart = <span class="hljs-keyword">if</span> @stepNum?
<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">#{lt}</span> <span class="hljs-subst">#{@toVar}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{@toVar}</span>"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> known
[<span class="hljs-keyword">from</span>, to] = [@fromNum, @toNum]
<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">#{lt}</span> <span class="hljs-subst">#{to}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{to}</span>"</span>
<span class="hljs-keyword">else</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>
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{@toVar}</span> : <span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{@toVar}</span>"</span></pre></div></div>
</li>
<li id="section-93">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-93">&#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-94">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-94">&#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-95">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-95">&#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>
result = o.scope.freeVariable <span class="hljs-string">'results'</span>
pre = <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span><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-96">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-96">&#182;</a>
</div>
<h3 id="slice">Slice</h3>
</div>
</li>
<li id="section-97">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-97">&#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-98">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-98">&#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
fromCompiled = <span class="hljs-keyword">from</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">from</span>.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">or</span> [@makeCode <span class="hljs-string">'0'</span>]</pre></div></div>
</li>
<li id="section-99">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-99">&#182;</a>
</div>
<p>TODO: jwalton - move this into the if?</p>
</div>
<div class="content"><div class='highlight'><pre> <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-100">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-100">&#182;</a>
</div>
<h3 id="obj">Obj</h3>
</div>
</li>
<li id="section-101">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-101">&#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-102">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#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">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()
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>
idt = o.indent += TAB
lastNoncom = @lastNonComment @properties
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> Comment <span class="hljs-keyword">or</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-string">"{<span class="hljs-subst">#{<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>"</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> lastNoncom <span class="hljs-keyword">or</span> prop <span class="hljs-keyword">instanceof</span> Comment
<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">or</span> prop <span class="hljs-keyword">instanceof</span> Comment <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> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
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> <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-string">"<span class="hljs-subst">#{<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>}</span>}"</span>
<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-103">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
</div>
<h3 id="arr">Arr</h3>
</div>
</li>
<li id="section-104">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#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>]
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
answer = []</pre></div></div>
</li>
<li id="section-105">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#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
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects
unwrappedObj = obj.unwrapAll()
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)
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledObjs
<span class="hljs-keyword">if</span> index
answer.push @makeCode <span class="hljs-string">", "</span>
answer.push fragments...
<span class="hljs-keyword">if</span> fragmentsToText(answer).indexOf(<span class="hljs-string">'\n'</span>) &gt;= <span class="hljs-number">0</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>
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-106">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-106">&#182;</a>
</div>
<h3 id="class">Class</h3>
</div>
</li>
<li id="section-107">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-107">&#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-108">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-108">&#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
<span class="hljs-keyword">if</span> executableBody <span class="hljs-keyword">or</span> @hasNameClash
@compileNode = @compileClassDeclaration
result = <span class="hljs-keyword">new</span> ExecutableClassBody(@, executableBody).compileToFragments o
@compileNode = @constructor::compileNode
<span class="hljs-keyword">else</span>
result = @compileClassDeclaration o</pre></div></div>
</li>
<li id="section-109">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-109">&#182;</a>
</div>
<p>Anonymous classes are only valid in expressions</p>
</div>
<div class="content"><div class='highlight'><pre> result = @wrapInParentheses result <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
<span class="hljs-keyword">if</span> @variable
assign = <span class="hljs-keyword">new</span> Assign @variable, <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">''</span>), <span class="hljs-literal">null</span>, { @moduleDeclaration }
[ assign.compileToFragments(o)..., result... ]
<span class="hljs-keyword">else</span>
result
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 o <span class="hljs-keyword">if</span> @boundMethods.length
o.indent += TAB
result = []
result.push @makeCode <span class="hljs-string">"class "</span>
result.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@name}</span> "</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-110">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-110">&#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>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> initializer[initializer.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">instanceof</span> Comment</pre></div></div>
</li>
<li id="section-111">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-111">&#182;</a>
</div>
<p>Try to keep comments with their subsequent assign</p>
</div>
<div class="content"><div class='highlight'><pre> exprs.pop()
initializer.pop()
start--
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
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> initializer[initializer.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">instanceof</span> Comment</pre></div></div>
</li>
<li id="section-112">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-112">&#182;</a>
</div>
<p>Try to keep comments with their subsequent assign</p>
</div>
<div class="content"><div class='highlight'><pre> initializer.pop()
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.bound <span class="hljs-keyword">and</span> method.isStatic
method.context = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method.bound
@boundMethods.push method.name
method.bound = <span class="hljs-literal">false</span>
<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-113">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-113">&#182;</a>
</div>
<p>Add an expression to the class initializer</p>
<p>NOTE Currently, only comments, methods and static methods are valid in ES class initializers.
When additional expressions become valid, this method should be updated to handle them.</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">switch</span>
<span class="hljs-keyword">when</span> node <span class="hljs-keyword">instanceof</span> Comment
node
<span class="hljs-keyword">when</span> @validInitializerMethod node
@addInitializerMethod node
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-114">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-114">&#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">false</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">true</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-115">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-115">&#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 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"><span class="hljs-params">(o)</span> -&gt;</span>
@ctor.thisAssignments = <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> @boundMethods <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
name = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> ThisLiteral, [ name ]).compile o
<span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{name}</span> = <span class="hljs-subst">#{utility <span class="hljs-string">'bind'</span>, o}</span>(<span class="hljs-subst">#{name}</span>, this)"</span>
<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>
@name = @class.name ? @defaultClassVariableName
directives = @walkBody()
@setContext()
ident = <span class="hljs-keyword">new</span> IdentifierLiteral @name
params = []
args = []
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 wrapper, args
@body.spaced = <span class="hljs-literal">true</span>
o.classScope = wrapper.makeScope o.scope
<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-116">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-116">&#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> Comment <span class="hljs-keyword">or</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
node.context = @name</pre></div></div>
</li>
<li id="section-117">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-117">&#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> assign <span class="hljs-keyword">instanceof</span> Comment</pre></div></div>
</li>
<li id="section-118">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-118">&#182;</a>
</div>
<p>Passthrough</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <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-119">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-119">&#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-120">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-120">&#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-121">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-121">&#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>()</pre></div></div>
</li>
<li id="section-122">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-122">&#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-123">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-123">&#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-124">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-124">&#182;</a>
</div>
<h3 id="assign">Assign</h3>
</div>
</li>
<li id="section-125">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-125">&#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-126">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-126">&#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-127">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-127">&#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-128">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-128">&#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-129">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-129">&#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>
<span class="hljs-keyword">return</span> @compileDestructuring o <span class="hljs-keyword">unless</span> @variable.isAssignable()
<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-130">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-130">&#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>
o.scope.find name.value
<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>
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">else</span> <span class="hljs-keyword">if</span> fragmentsToText(compiledName) <span class="hljs-keyword">in</span> JS_FORBIDDEN
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-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-131">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-131">&#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.</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> @param)
@wrapInParentheses answer
<span class="hljs-keyword">else</span>
answer</pre></div></div>
</li>
<li id="section-132">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-132">&#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-133">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-133">&#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-134">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-134">&#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>
isObject = @variable.isObject()</pre></div></div>
</li>
<li id="section-135">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-135">&#182;</a>
</div>
<p>Special case for when theres only one thing destructured off of
something. <code>{a} = b</code>, <code>[a] = b</code>, <code>{a: b} = c</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> top <span class="hljs-keyword">and</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">not</span> <span class="hljs-keyword">instanceof</span> Splat</pre></div></div>
</li>
<li id="section-136">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-136">&#182;</a>
</div>
<p>Pick the property straight off the value when theres just one to pick
(no need to cache the value into a variable).</p>
</div>
<div class="content"><div class='highlight'><pre> defaultValue = <span class="hljs-literal">undefined</span>
<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></pre></div></div>
</li>
<li id="section-137">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-137">&#182;</a>
</div>
<p>A regular object pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> {variable: {base: idx}, value: obj} = obj
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
idx = <span class="hljs-keyword">if</span> isObject</pre></div></div>
</li>
<li id="section-138">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-138">&#182;</a>
</div>
<p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
obj.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName obj.unwrap().value
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-139">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-139">&#182;</a>
</div>
<p>A regular array pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> NumberLiteral <span class="hljs-number">0</span>
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
value = <span class="hljs-keyword">new</span> Value value
value.properties.push <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
message = isUnassignable obj.unwrap().value
obj.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">if</span> defaultValue
defaultValue.isDefaultValue = <span class="hljs-literal">yes</span>
value = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, value, defaultValue
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Assign(obj, value, <span class="hljs-literal">null</span>, param: @param).compileToFragments o, LEVEL_TOP
vvar = value.compileToFragments o, LEVEL_LIST
vvarText = fragmentsToText vvar
assigns = []
expandedIdx = <span class="hljs-literal">false</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>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</pre></div></div>
</li>
<li id="section-141">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-141">&#182;</a>
</div>
<p>And here comes the big loop that handles all of these cases:
<code>[a, b] = c</code>
<code>[a..., b] = c</code>
<code>[..., a, b] = c</code>
<code>[@a, b] = c</code>
<code>[a = 1, b] = c</code>
<code>{a, b} = c</code>
<code>{@a, b} = c</code>
<code>{a = 1, b} = c</code>
etc.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects
idx = i
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Splat
name = obj.name.unwrap().value
obj = obj.unwrap()
val = <span class="hljs-string">"<span class="hljs-subst">#{olen}</span> &lt;= <span class="hljs-subst">#{vvarText}</span>.length ? <span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call(<span class="hljs-subst">#{vvarText}</span>, <span class="hljs-subst">#{i}</span>"</span>
rest = olen - i - <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> rest <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
val += <span class="hljs-string">", <span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>) : (<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{i}</span>, [])"</span>
<span class="hljs-keyword">else</span>
val += <span class="hljs-string">") : []"</span>
val = <span class="hljs-keyword">new</span> Literal val
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion
rest = olen - i - <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> rest <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> rest <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{vvarText}</span>.length - 1"</span>
<span class="hljs-keyword">else</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
val = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>"</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>
assigns.push val.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">or</span> obj <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">"multiple splats/expansions are disallowed in an assignment"</span>
defaultValue = <span class="hljs-literal">undefined</span>
<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></pre></div></div>
</li>
<li id="section-142">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-142">&#182;</a>
</div>
<p>A regular object pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> {variable: {base: idx}, value: obj} = obj
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
idx = <span class="hljs-keyword">if</span> isObject</pre></div></div>
</li>
<li id="section-143">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-143">&#182;</a>
</div>
<p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
obj.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName obj.unwrap().value
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-144">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-144">&#182;</a>
</div>
<p>A regular array pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> Literal expandedIdx <span class="hljs-keyword">or</span> idx
name = obj.unwrap().value
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
val = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarText), [<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">if</span> defaultValue
defaultValue.isDefaultValue = <span class="hljs-literal">yes</span>
val = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, val, defaultValue
<span class="hljs-keyword">if</span> name?
message = isUnassignable name
obj.error message <span class="hljs-keyword">if</span> message
assigns.push <span class="hljs-keyword">new</span> Assign(obj, val, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST
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-145">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-145">&#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-146">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-146">&#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-147">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-147">&#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-148">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-148">&#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()
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">"[].splice.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-149">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-149">&#182;</a>
</div>
<h3 id="code">Code</h3>
</div>
</li>
<li id="section-150">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-150">&#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, tag)</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 = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'boundfunc'</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-151">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-151">&#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-152">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-152">&#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) -&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
param.renameParam node, target
thisAssignments.push <span class="hljs-keyword">new</span> Assign node, target</pre></div></div>
</li>
<li id="section-153">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-153">&#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-154">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-154">&#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-155">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-155">&#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-literal">null</span>, param: <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
params.push ref = param.asReference o
splatParamName = fragmentsToText ref.compileNode 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-literal">null</span>, param: <span class="hljs-literal">yes</span>
<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-156">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-156">&#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-157">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-157">&#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, <span class="hljs-literal">null</span>, param: <span class="hljs-literal">yes</span>
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-literal">yes</span></pre></div></div>
</li>
<li id="section-158">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-158">&#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-159">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-159">&#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-160">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-160">&#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-161">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-161">&#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>
param.name.eachName (prop) -&gt;
o.scope.parameter prop.value
<span class="hljs-keyword">else</span>
o.scope.parameter fragmentsToText (<span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">then</span> param <span class="hljs-keyword">else</span> ref).compileToFragments o
params.push ref
<span class="hljs-keyword">else</span>
paramsAfterSplat.push param</pre></div></div>
</li>
<li id="section-162">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-162">&#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-163">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-163">&#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-164">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-164">&#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-165">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-165">&#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-166">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-166">&#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...
@body.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> @noReturn</pre></div></div>
</li>
<li id="section-167">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-167">&#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>]
<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
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>
signature.push param.compileToFragments(o)...
signature.push @makeCode <span class="hljs-string">')'</span>
body = @body.compileWithDeclarations o <span class="hljs-keyword">unless</span> @body.isEmpty()</pre></div></div>
</li>
<li id="section-168">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-168">&#182;</a>
</div>
<p>We need to compile the body before method names to ensure super 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> [@makeCode(@tab), 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-169">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-169">&#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-170">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-170">&#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-171">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-171">&#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">true</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
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-172">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-172">&#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-173">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-173">&#182;</a>
</div>
<h3 id="param">Param</h3>
</div>
</li>
<li id="section-174">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-174">&#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
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-175">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-175">&#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)</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, @</pre></div></div>
</li>
<li id="section-176">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-176">&#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-177">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-177">&#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-178">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-178">&#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-179">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-179">&#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-180">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-180">&#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
@eachName iterator, obj.value.unwrap()</pre></div></div>
</li>
<li id="section-181">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-181">&#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-182">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-182">&#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-183">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-183">&#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</pre></div></div>
</li>
<li id="section-184">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-184">&#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">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-185">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-185">&#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>
<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-186">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-186">&#182;</a>
</div>
<h3 id="splat">Splat</h3>
</div>
</li>
<li id="section-187">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-187">&#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>
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())
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
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@name.assigns name
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[ @makeCode(<span class="hljs-string">'...'</span>)
@name.compileToFragments(o)... ]
unwrap: <span class="hljs-function">-&gt;</span> @name</pre></div></div>
</li>
<li id="section-188">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-188">&#182;</a>
</div>
<h3 id="expansion">Expansion</h3>
</div>
</li>
<li id="section-189">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-189">&#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-190">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-190">&#182;</a>
</div>
<h3 id="while">While</h3>
</div>
</li>
<li id="section-191">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-191">&#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 loop: <span class="hljs-literal">yes</span>
<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-192">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-192">&#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-193">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-193">&#182;</a>
</div>
<h3 id="op">Op</h3>
</div>
</li>
<li id="section-194">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-194">&#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">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">return</span> first.newInstance() <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.<span class="hljs-keyword">do</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.isNew
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>
<span class="hljs-keyword">super</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-195">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-195">&#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-196">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-196">&#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-197">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-197">&#182;</a>
</div>
<p>Am I capable of
<a href="http://docs.python.org/reference/expressions.html#notin">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-198">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-198">&#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-199">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-199">&#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-200">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-200">&#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-201">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-201">&#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-202">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-202">&#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-203">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-203">&#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-204">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-204">&#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-205">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-205">&#182;</a>
</div>
<h3 id="try">Try</h3>
</div>
</li>
<li id="section-206">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-206">&#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-207">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-207">&#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-208">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-208">&#182;</a>
</div>
<h3 id="throw">Throw</h3>
</div>
</li>
<li id="section-209">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-209">&#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-210">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-210">&#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>
[].concat @makeCode(@tab + <span class="hljs-string">"throw "</span>), @expression.compileToFragments(o), @makeCode(<span class="hljs-string">";"</span>)</pre></div></div>
</li>
<li id="section-211">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-211">&#182;</a>
</div>
<h3 id="existence">Existence</h3>
</div>
</li>
<li id="section-212">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-212">&#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>
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-213">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-213">&#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-214">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-214">&#182;</a>
</div>
<h3 id="parens">Parens</h3>
</div>
</li>
<li id="section-215">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-215">&#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()
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isAtomic()
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> (expr <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">or</span> expr <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">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-216">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-216">&#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-217">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-217">&#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></pre></div></div>
</li>
<li id="section-218">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-218">&#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 = []
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
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
elements.push node
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span>
<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">for</span> element <span class="hljs-keyword">in</span> elements
<span class="hljs-keyword">if</span> element <span class="hljs-keyword">instanceof</span> StringLiteral
value = element.value[<span class="hljs-number">1.</span>..<span class="hljs-number">-1</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>Backticks and <code>${</code> inside template literals must be escaped.</p>
</div>
<div class="content"><div class='highlight'><pre> value = 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 @makeCode value
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">'${'</span>
fragments.push element.compileToFragments(o, LEVEL_PAREN)...
fragments.push @makeCode <span class="hljs-string">'}'</span>
fragments.push @makeCode <span class="hljs-string">'`'</span>
fragments</pre></div></div>
</li>
<li id="section-220">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-220">&#182;</a>
</div>
<h3 id="for">For</h3>
</div>
</li>
<li id="section-221">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-221">&#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">false</span>
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-222">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-222">&#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>
defPartFragments = [].concat @makeCode(defPart), @pluckDirectCall(o, body)
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>)
[].concat defPartFragments, @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{resultPart <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span><span class="hljs-subst">#{@tab}</span>for ("</span>),
forPartFragments, @makeCode(<span class="hljs-string">") {<span class="hljs-subst">#{guardPart}</span><span class="hljs-subst">#{varPart}</span>"</span>), bodyFragments,
@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>}<span class="hljs-subst">#{returnResult <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span>"</span>)
pluckDirectCall: <span class="hljs-function"><span class="hljs-params">(o, body)</span> -&gt;</span>
defs = []
<span class="hljs-keyword">for</span> expr, idx <span class="hljs-keyword">in</span> body.expressions
expr = expr.unwrapAll()
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> expr <span class="hljs-keyword">instanceof</span> Call
val = expr.variable?.unwrapAll()
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> (val <span class="hljs-keyword">instanceof</span> Code) <span class="hljs-keyword">or</span>
(val <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span>
val.base?.unwrapAll() <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span>
val.properties.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span>
val.properties[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">in</span> [<span class="hljs-string">'call'</span>, <span class="hljs-string">'apply'</span>])
fn = val.base?.unwrapAll() <span class="hljs-keyword">or</span> val
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'fn'</span>
base = <span class="hljs-keyword">new</span> Value ref
<span class="hljs-keyword">if</span> val.base
[val.base, base] = [base, val]
body.expressions[idx] = <span class="hljs-keyword">new</span> Call base, expr.args
defs = defs.concat @makeCode(@tab), (<span class="hljs-keyword">new</span> Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), @makeCode(<span class="hljs-string">';\n'</span>)
defs</pre></div></div>
</li>
<li id="section-223">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-223">&#182;</a>
</div>
<h3 id="switch">Switch</h3>
</div>
</li>
<li id="section-224">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-224">&#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 = @lastNonComment 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> 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-225">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-225">&#182;</a>
</div>
<h3 id="if">If</h3>
</div>
</li>
<li id="section-226">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-226">&#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
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-227">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-227">&#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-228">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-228">&#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-229">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-229">&#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-230">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-230">&#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-231">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-231">&#182;</a>
</div>
<h2 id="constants">Constants</h2>
</div>
</li>
<li id="section-232">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-232">&#182;</a>
</div>
</div>
<div class="content"><div class='highlight'><pre>
UTILITIES =</pre></div></div>
</li>
<li id="section-233">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-233">&#182;</a>
</div>
<p>Correctly set up a prototype chain for inheritance, including a reference
to the superclass for <code>super()</code> calls, and copies of any static properties.</p>
</div>
<div class="content"><div class='highlight'><pre> extend: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-string">"
function(child, parent) {
for (var key in parent) {
if (<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
return child;
}
"</span></pre></div></div>
</li>
<li id="section-234">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-234">&#182;</a>
</div>
<p>Create a function bound to the current value of “this”.</p>
</div>
<div class="content"><div class='highlight'><pre> bind: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'
function(fn, me){
return function(){
return fn.apply(me, arguments);
};
}
'</span></pre></div></div>
</li>
<li id="section-235">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-235">&#182;</a>
</div>
<p>Discover if an item is in an array.</p>
</div>
<div class="content"><div class='highlight'><pre> indexOf: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"
[].indexOf || function(item) {
for (var i = 0, l = this.length; i &lt; l; i++) {
if (i in this &amp;&amp; this[i] === item) return i;
}
return -1;
}
"</span>
modulo: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"""
function(a, b) { return (+a % (b = +b) + b) % b; }
"""</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>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>
slice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">'[].slice'</span></pre></div></div>
</li>
<li id="section-237">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-237">&#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-238">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-238">&#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-239">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-239">&#182;</a>
</div>
<h2 id="helper-functions">Helper Functions</h2>
</div>
</li>
<li id="section-240">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-240">&#182;</a>
</div>
</div>
</li>
<li id="section-241">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-241">&#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)</span> -&gt;</span>
code = code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'$&amp;'</span> + tab
code.replace <span class="hljs-regexp">/\s+$/</span>, <span class="hljs-string">''</span>
<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-242">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-242">&#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>