jashkenas--coffeescript/docs/v2/annotated-source/nodes.html

10786 lines
585 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="sswrap ">
<a class="ss" href="#section-1">&#x00a7;</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>
<span class="hljs-built_in">Error</span>.stackTraceLimit = <span class="hljs-literal">Infinity</span>
{Scope} = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./scope&#x27;</span>
{isUnassignable, JS_FORBIDDEN} = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./lexer&#x27;</span></pre></div></div>
</li>
<li id="section-2">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-2">&#x00a7;</a>
</div>
<p>Import the helpers we plan to use.</p>
</div>
<div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, some,
addDataToNode, attachCommentsToNode, locationDataToString,
throwSyntaxError, replaceUnicodeCodePointEscapes,
isFunction, isPlainObject, isNumber, parseNumber} = <span class="hljs-built_in">require</span> <span class="hljs-string">&#x27;./helpers&#x27;</span></pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-3">&#x00a7;</a>
</div>
<p>Functions required by parser.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.extend = extend
<span class="hljs-built_in">exports</span>.addDataToNode = addDataToNode</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-4">&#x00a7;</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> this
<span class="hljs-function"><span class="hljs-title">NEGATE</span> = -&gt;</span> @negated = <span class="hljs-keyword">not</span> @negated; this</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-5">&#x00a7;</a>
</div>
<h3 id="codefragment">CodeFragment</h3>
</div>
</li>
<li id="section-6">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-6">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">&quot;<span class="hljs-subst">#{code}</span>&quot;</span>
@type = parent?.constructor?.name <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;unknown&#x27;</span>
@locationData = parent?.locationData
@comments = parent?.comments
toString: <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-7">&#x00a7;</a>
</div>
<p>This is only intended for debugging.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-string">&quot;<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">&quot;: &quot;</span> + locationDataToString(@locationData) <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>&quot;</span></pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-8">&#x00a7;</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">&#x27;&#x27;</span>)</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-9">&#x00a7;</a>
</div>
<h3 id="base">Base</h3>
</div>
</li>
<li id="section-10">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-10">&#x00a7;</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><span class="hljs-built_in">exports</span>.Base = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Base</span></span>
compile: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
fragmentsToText @compileToFragments o, lvl</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-11">&#x00a7;</a>
</div>
<p>Occasionally a node is compiled multiple times, for example to get the name
of a variable to add to scope tracking. When we know that a “premature”
compilation wont result in comments being output, set those comments aside
so that theyre preserved for a later <code>compile</code> call that will result in
the comments being included in the output.</p>
</div>
<div class="content"><div class='highlight'><pre> compileWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl, method = <span class="hljs-string">&#x27;compile&#x27;</span>)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @comments
@ignoreTheseCommentsTemporarily = @comments
<span class="hljs-keyword">delete</span> @comments
unwrapped = @unwrapAll()
<span class="hljs-keyword">if</span> unwrapped.comments
unwrapped.ignoreTheseCommentsTemporarily = unwrapped.comments
<span class="hljs-keyword">delete</span> unwrapped.comments
fragments = @[method] o, lvl
<span class="hljs-keyword">if</span> @ignoreTheseCommentsTemporarily
@comments = @ignoreTheseCommentsTemporarily
<span class="hljs-keyword">delete</span> @ignoreTheseCommentsTemporarily
<span class="hljs-keyword">if</span> unwrapped.ignoreTheseCommentsTemporarily
unwrapped.comments = unwrapped.ignoreTheseCommentsTemporarily
<span class="hljs-keyword">delete</span> unwrapped.ignoreTheseCommentsTemporarily
fragments
compileNodeWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
@compileWithoutComments o, lvl, <span class="hljs-string">&#x27;compileNode&#x27;</span></pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-12">&#x00a7;</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> this
node.tab = o.indent
fragments = <span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.isStatement(o)
node.compileNode o
<span class="hljs-keyword">else</span>
node.compileClosure o
@compileCommentFragments o, node, fragments
fragments
compileToFragmentsWithoutComments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
@compileWithoutComments o, lvl, <span class="hljs-string">&#x27;compileToFragments&#x27;</span></pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-13">&#x00a7;</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>
@checkForPureStatementInExpression()
o.sharedScope = <span class="hljs-literal">yes</span>
func = <span class="hljs-keyword">new</span> Code [], Block.wrap [this]
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">&#x27;apply&#x27;</span>
args.push <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">&#x27;arguments&#x27;</span>
<span class="hljs-keyword">else</span>
meth = <span class="hljs-string">&#x27;call&#x27;</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">&quot;(yield* &quot;</span>
parts.push @makeCode <span class="hljs-string">&quot;)&quot;</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">&quot;(await &quot;</span>
parts.push @makeCode <span class="hljs-string">&quot;)&quot;</span>
parts
compileCommentFragments: <span class="hljs-function"><span class="hljs-params">(o, node, fragments)</span> -&gt;</span>
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">unless</span> node.comments</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-14">&#x00a7;</a>
</div>
<p>This is where comments, that are attached to nodes as a <code>comments</code>
property, become <code>CodeFragment</code>s. “Inline block comments,” e.g.
<code>/* */</code>-delimited comments that are interspersed within code on a line,
are added to the current <code>fragments</code> stream. All other fragments are
attached as properties to the nearest preceding or following fragment,
to remain stowaways until they get properly output in <code>compileComments</code>
later on.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">unshiftCommentFragment</span> = <span class="hljs-params">(commentFragment)</span> -&gt;</span>
<span class="hljs-keyword">if</span> commentFragment.unshift</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-15">&#x00a7;</a>
</div>
<p>Find the first non-comment fragment and insert <code>commentFragment</code>
before it.</p>
</div>
<div class="content"><div class='highlight'><pre> unshiftAfterComments fragments, commentFragment
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
precedingFragment = fragments[fragments.length - <span class="hljs-number">1</span>]
<span class="hljs-keyword">if</span> commentFragment.newLine <span class="hljs-keyword">and</span> precedingFragment.code <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">and</span>
<span class="hljs-keyword">not</span> <span class="hljs-regexp">/\n\s*$/</span>.test precedingFragment.code
commentFragment.code = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{commentFragment.code}</span>&quot;</span>
fragments.push commentFragment
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments <span class="hljs-keyword">when</span> comment <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> @compiledComments
@compiledComments.push comment <span class="hljs-comment"># Dont output this comment twice.</span></pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-16">&#x00a7;</a>
</div>
<p>For block/here comments, denoted by <code>###</code>, that are inline comments
like <code>1 + ### comment ### 2</code>, create fragments and insert them into
the fragments array.
Otherwise attach comment fragments to their closest fragment for now,
so they can be inserted into the output later after all the newlines
have been added.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> comment.here <span class="hljs-comment"># Block comment, delimited by `###`.</span>
commentFragment = <span class="hljs-keyword">new</span> HereComment(comment).compileNode o
<span class="hljs-keyword">else</span> <span class="hljs-comment"># Line comment, delimited by `#`.</span>
commentFragment = <span class="hljs-keyword">new</span> LineComment(comment).compileNode o
<span class="hljs-keyword">if</span> (commentFragment.isHereComment <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> commentFragment.newLine) <span class="hljs-keyword">or</span>
node.includeCommentFragments()</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-17">&#x00a7;</a>
</div>
<p>Inline block comments, like <code>1 + /* comment */ 2</code>, or a node whose
<code>compileToFragments</code> method has logic for outputting comments.</p>
</div>
<div class="content"><div class='highlight'><pre> unshiftCommentFragment commentFragment
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> commentFragment.unshift
fragments[<span class="hljs-number">0</span>].precedingComments ?= []
fragments[<span class="hljs-number">0</span>].precedingComments.push commentFragment
<span class="hljs-keyword">else</span>
fragments[fragments.length - <span class="hljs-number">1</span>].followingComments ?= []
fragments[fragments.length - <span class="hljs-number">1</span>].followingComments.push commentFragment
fragments</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-18">&#x00a7;</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 this <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">&#x27;ref&#x27;</span>
sub = <span class="hljs-keyword">new</span> Assign ref, this
<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> this
[ref, ref]</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-19">&#x00a7;</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 to the source position. This is used extensively to deal with executable
class bodies in classes.</p>
<p>Calling this method mutates the node, proxying the <code>compileNode</code> and <code>compileToFragments</code>
methods to store their result for later replacing the <code>target</code> node, which is returned by the
call.</p>
</div>
<div class="content"><div class='highlight'><pre> hoist: <span class="hljs-function">-&gt;</span>
@hoisted = <span class="hljs-literal">yes</span>
target = <span class="hljs-keyword">new</span> HoistTarget @
compileNode = @compileNode
compileToFragments = @compileToFragments
@compileNode = <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
target.update compileNode, o
@compileToFragments = <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
target.update compileToFragments, o
target
cacheToCodeFragments: <span class="hljs-function"><span class="hljs-params">(cacheValues)</span> -&gt;</span>
[fragmentsToText(cacheValues[<span class="hljs-number">0</span>]), fragmentsToText(cacheValues[<span class="hljs-number">1</span>])]</pre></div></div>
</li>
<li id="section-20">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-20">&#x00a7;</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. <code>If</code>, <code>For</code>).</p>
</div>
<div class="content"><div class='highlight'><pre> makeReturn: <span class="hljs-function"><span class="hljs-params">(results, mark)</span> -&gt;</span>
<span class="hljs-keyword">if</span> mark</pre></div></div>
</li>
<li id="section-21">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-21">&#x00a7;</a>
</div>
<p>Mark this node as implicitly returned, so that it can be part of the
node metadata returned in the AST.</p>
</div>
<div class="content"><div class='highlight'><pre> @canBeReturned = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span>
node = @unwrapAll()
<span class="hljs-keyword">if</span> results
<span class="hljs-keyword">new</span> Call <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">&quot;<span class="hljs-subst">#{results}</span>.push&quot;</span>), [node]
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Return node</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-22">&#x00a7;</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-23">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-23">&#x00a7;</a>
</div>
<p>Pull out the last node of a node list.</p>
</div>
<div class="content"><div class='highlight'><pre> lastNode: <span class="hljs-function"><span class="hljs-params">(list)</span> -&gt;</span>
<span class="hljs-keyword">if</span> list.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">else</span> list[list.length - <span class="hljs-number">1</span>]</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-24">&#x00a7;</a>
</div>
<p>Debugging 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">&#x27;&#x27;</span>, name = @constructor.name)</span> -&gt;</span>
tree = <span class="hljs-string">&#x27;\n&#x27;</span> + idt + name
tree += <span class="hljs-string">&#x27;?&#x27;</span> <span class="hljs-keyword">if</span> @soak
@eachChild (node) -&gt; tree += node.toString idt + TAB
tree
checkForPureStatementInExpression: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> jumpNode = @jumps()
jumpNode.error <span class="hljs-string">&#x27;cannot use a pure statement in an expression&#x27;</span></pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-25">&#x00a7;</a>
</div>
<p>Plain JavaScript object representation of the node, that can be serialized
as JSON. This is what the <code>ast</code> option in the Node API returns.
We try to follow the <a href="https://github.com/babel/babel/blob/master/packages/babel-parser/ast/spec.md">Babel AST spec</a>
as closely as possible, for improved interoperability with other tools.
<strong>WARNING: DO NOT OVERRIDE THIS METHOD IN CHILD CLASSES.</strong>
Only override the component <code>ast*</code> methods as needed.</p>
</div>
<div class="content"><div class='highlight'><pre> ast: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-26">&#x00a7;</a>
</div>
<p>Merge <code>level</code> into <code>o</code> and perform other universal checks.</p>
</div>
<div class="content"><div class='highlight'><pre> o = @astInitialize o, level</pre></div></div>
</li>
<li id="section-27">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-27">&#x00a7;</a>
</div>
<p>Create serializable representation of this node.</p>
</div>
<div class="content"><div class='highlight'><pre> astNode = @astNode o</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-28">&#x00a7;</a>
</div>
<p>Mark AST nodes that correspond to expressions that (implicitly) return.
We cant do this as part of <code>astNode</code> because we need to assemble child
nodes first before marking the parent being returned.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @astNode? <span class="hljs-keyword">and</span> @canBeReturned
<span class="hljs-built_in">Object</span>.assign astNode, {returns: <span class="hljs-literal">yes</span>}
astNode
astInitialize: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
o = <span class="hljs-built_in">Object</span>.assign {}, o
o.level = level <span class="hljs-keyword">if</span> level?
<span class="hljs-keyword">if</span> o.level &gt; LEVEL_TOP
@checkForPureStatementInExpression()</pre></div></div>
</li>
<li id="section-29">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-29">&#x00a7;</a>
</div>
<p><code>@makeReturn</code> must be called before <code>astProperties</code>, because the latter may call
<code>.ast()</code> for child nodes and those nodes would need the return logic from <code>makeReturn</code>
already executed by then.</p>
</div>
<div class="content"><div class='highlight'><pre> @makeReturn <span class="hljs-literal">null</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @isStatement(o) <span class="hljs-keyword">and</span> o.level <span class="hljs-keyword">isnt</span> LEVEL_TOP <span class="hljs-keyword">and</span> o.scope?
o
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-30">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-30">&#x00a7;</a>
</div>
<p>Every abstract syntax tree node object has four categories of properties:</p>
<ul>
<li>type, stored in the <code>type</code> field and a string like <code>NumberLiteral</code>.</li>
<li>location data, stored in the <code>loc</code>, <code>start</code>, <code>end</code> and <code>range</code> fields.</li>
<li>properties specific to this node, like <code>parsedValue</code>.</li>
<li>properties that are themselves child nodes, like <code>body</code>.
These fields are all intermixed in the Babel spec; <code>type</code> and <code>start</code> and
<code>parsedValue</code> are all top level fields in the AST node object. We have
separate methods for returning each category, that we merge together here.</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-built_in">Object</span>.assign {}, {type: @astType(o)}, @astProperties(o), @astLocationData()</pre></div></div>
</li>
<li id="section-31">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-31">&#x00a7;</a>
</div>
<p>By default, a node class has no specific properties.</p>
</div>
<div class="content"><div class='highlight'><pre> astProperties: <span class="hljs-function">-&gt;</span> {}</pre></div></div>
</li>
<li id="section-32">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-32">&#x00a7;</a>
</div>
<p>By default, a node classs AST <code>type</code> is its class name.</p>
</div>
<div class="content"><div class='highlight'><pre> astType: <span class="hljs-function">-&gt;</span> @constructor.name</pre></div></div>
</li>
<li id="section-33">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-33">&#x00a7;</a>
</div>
<p>The AST location data is a rearranged version of our Jison location data,
mutated into the structure that the Babel spec uses.</p>
</div>
<div class="content"><div class='highlight'><pre> astLocationData: <span class="hljs-function">-&gt;</span>
jisonLocationDataToAstLocationData @locationData</pre></div></div>
</li>
<li id="section-34">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-34">&#x00a7;</a>
</div>
<p>Determines whether an AST node needs an <code>ExpressionStatement</code> wrapper.
Typically matches our <code>isStatement()</code> logic but this allows overriding.</p>
</div>
<div class="content"><div class='highlight'><pre> isStatementAst: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@isStatement o</pre></div></div>
</li>
<li id="section-35">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-35">&#x00a7;</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> this <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> this <span class="hljs-keyword">if</span> func(child) <span class="hljs-keyword">is</span> <span class="hljs-literal">false</span>
this
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-36">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-36">&#x00a7;</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> <span class="hljs-built_in">Array</span>.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">&#x27;!&#x27;</span>, this
unwrapAll: <span class="hljs-function">-&gt;</span>
node = this
<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-37">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-37">&#x00a7;</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-38">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-38">&#x00a7;</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-39">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-39">&#x00a7;</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-40">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-40">&#x00a7;</a>
</div>
<p>Track comments that have been compiled into fragments, to avoid outputting
them twice.</p>
</div>
<div class="content"><div class='highlight'><pre> compiledComments: []</pre></div></div>
</li>
<li id="section-41">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-41">&#x00a7;</a>
</div>
<p><code>includeCommentFragments</code> lets <code>compileCommentFragments</code> know whether this node
has special awareness of how to handle comments within its output.</p>
</div>
<div class="content"><div class='highlight'><pre> includeCommentFragments: NO</pre></div></div>
</li>
<li id="section-42">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-42">&#x00a7;</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>, <code>continue</code>, or <code>return</code>)
that jumps out of the normal flow of control and cant be used as a value.
(Note that <code>throw</code> is not considered a flow control construct.)
This is important because flow control in the middle of an expression
makes no sense; we have to disallow it.</p>
</div>
<div class="content"><div class='highlight'><pre> jumps: NO</pre></div></div>
</li>
<li id="section-43">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-43">&#x00a7;</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-44">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-44">&#x00a7;</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-45">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-45">&#x00a7;</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, force)</span> -&gt;</span>
@forceUpdateLocation = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> force
<span class="hljs-keyword">return</span> this <span class="hljs-keyword">if</span> @locationData <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @forceUpdateLocation
<span class="hljs-keyword">delete</span> @forceUpdateLocation
@locationData = locationData
@eachChild (child) -&gt;
child.updateLocationDataIfMissing locationData</pre></div></div>
</li>
<li id="section-46">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-46">&#x00a7;</a>
</div>
<p>Add location data from another node</p>
</div>
<div class="content"><div class='highlight'><pre> withLocationDataFrom: <span class="hljs-function"><span class="hljs-params">({locationData})</span> -&gt;</span>
@updateLocationDataIfMissing locationData</pre></div></div>
</li>
<li id="section-47">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-47">&#x00a7;</a>
</div>
<p>Add location data and comments from another node</p>
</div>
<div class="content"><div class='highlight'><pre> withLocationDataAndCommentsFrom: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
@withLocationDataFrom node
{comments} = node
@comments = comments <span class="hljs-keyword">if</span> comments?.length
this</pre></div></div>
</li>
<li id="section-48">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-48">&#x00a7;</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 this, code
wrapInParentheses: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">&#x27;(&#x27;</span>), fragments..., @makeCode(<span class="hljs-string">&#x27;)&#x27;</span>)]
wrapInBraces: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">&#x27;{&#x27;</span>), fragments..., @makeCode(<span class="hljs-string">&#x27;}&#x27;</span>)]</pre></div></div>
</li>
<li id="section-49">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-49">&#x00a7;</a>
</div>
<p><code>fragmentsList</code> is an array of arrays of fragments. Each array in fragmentsList will be
concatenated together, with <code>joinStr</code> added in between each, to produce a final flat array
of fragments.</p>
</div>
<div class="content"><div class='highlight'><pre> joinFragmentArrays: <span class="hljs-function"><span class="hljs-params">(fragmentsList, joinStr)</span> -&gt;</span>
answer = []
<span class="hljs-keyword">for</span> fragments, i <span class="hljs-keyword">in</span> fragmentsList
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push @makeCode joinStr
answer = answer.concat fragments
answer</pre></div></div>
</li>
<li id="section-50">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-50">&#x00a7;</a>
</div>
<h3 id="hoisttarget">HoistTarget</h3>
</div>
</li>
<li id="section-51">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-51">&#x00a7;</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><span class="hljs-built_in">exports</span>.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-52">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-52">&#x00a7;</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>
super()</pre></div></div>
</li>
<li id="section-53">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-53">&#x00a7;</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-54">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-54">&#x00a7;</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-55">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-55">&#x00a7;</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-56">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-56">&#x00a7;</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-57">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-57">&#x00a7;</a>
</div>
<h3 id="root">Root</h3>
</div>
</li>
<li id="section-58">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-58">&#x00a7;</a>
</div>
<p>The root node of the node tree</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Root = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Root</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>
super()
@isAsync = (<span class="hljs-keyword">new</span> Code [], @body).isAsync
children: [<span class="hljs-string">&#x27;body&#x27;</span>]</pre></div></div>
</li>
<li id="section-59">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-59">&#x00a7;</a>
</div>
<p>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> compileNode: <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">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> TAB
o.level = LEVEL_TOP
o.compiling = <span class="hljs-literal">yes</span>
@initializeScope o
fragments = @body.compileRoot o
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> o.bare
functionKeyword = <span class="hljs-string">&quot;<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isAsync <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;async &#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>function&quot;</span>
[].concat @makeCode(<span class="hljs-string">&quot;(<span class="hljs-subst">#{functionKeyword}</span>() {\n&quot;</span>), fragments, @makeCode(<span class="hljs-string">&quot;\n}).call(this);\n&quot;</span>)
initializeScope: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, @body, <span class="hljs-literal">null</span>, o.referencedVars ? []</pre></div></div>
</li>
<li id="section-60">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-60">&#x00a7;</a>
</div>
<p>Mark given local variables in the root scope as parameters so they dont
end up being declared on the root 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> []
commentsAst: <span class="hljs-function">-&gt;</span>
@allComments ?=
<span class="hljs-keyword">for</span> commentToken <span class="hljs-keyword">in</span> (@allCommentTokens ? []) <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> commentToken.heregex
<span class="hljs-keyword">if</span> commentToken.here
<span class="hljs-keyword">new</span> HereComment commentToken
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> LineComment commentToken
comment.ast() <span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> @allComments
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.level = LEVEL_TOP
@initializeScope o
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;File&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@body.isRootBlock = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span>
program: <span class="hljs-built_in">Object</span>.assign @body.ast(o), @astLocationData()
comments: @commentsAst()</pre></div></div>
</li>
<li id="section-61">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-61">&#x00a7;</a>
</div>
<h3 id="block">Block</h3>
</div>
</li>
<li id="section-62">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-62">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
@expressions = compact flatten nodes <span class="hljs-keyword">or</span> []
children: [<span class="hljs-string">&#x27;expressions&#x27;</span>]</pre></div></div>
</li>
<li id="section-63">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-63">&#x00a7;</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
this</pre></div></div>
</li>
<li id="section-64">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-64">&#x00a7;</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-65">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-65">&#x00a7;</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
this</pre></div></div>
</li>
<li id="section-66">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-66">&#x00a7;</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> this</pre></div></div>
</li>
<li id="section-67">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-67">&#x00a7;</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-68">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-68">&#x00a7;</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">(results, mark)</span> -&gt;</span>
len = @expressions.length
[..., lastExp] = @expressions
lastExp = lastExp?.unwrap() <span class="hljs-keyword">or</span> <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-69">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-69">&#x00a7;</a>
</div>
<p>We also need to check that were not returning a JSX tag if theres an
adjacent one at the same level; JSX doesnt allow that.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> lastExp <span class="hljs-keyword">and</span> lastExp <span class="hljs-keyword">instanceof</span> Parens <span class="hljs-keyword">and</span> lastExp.body.expressions.length &gt; <span class="hljs-number">1</span>
{body:{expressions}} = lastExp
[..., penult, last] = expressions
penult = penult.unwrap()
last = last.unwrap()
<span class="hljs-keyword">if</span> penult <span class="hljs-keyword">instanceof</span> JSXElement <span class="hljs-keyword">and</span> last <span class="hljs-keyword">instanceof</span> JSXElement
expressions[expressions.length - <span class="hljs-number">1</span>].error <span class="hljs-string">&#x27;Adjacent JSX elements must be wrapped in an enclosing tag&#x27;</span>
<span class="hljs-keyword">if</span> mark
@expressions[len - <span class="hljs-number">1</span>]?.makeReturn results, mark
<span class="hljs-keyword">return</span>
<span class="hljs-keyword">while</span> len--
expr = @expressions[len]
@expressions[len] = expr.makeReturn results
@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>
this
compile: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Root(this).withLocationDataFrom(this).compile o, lvl <span class="hljs-keyword">unless</span> o.scope
super o, lvl</pre></div></div>
</li>
<li id="section-70">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-70">&#x00a7;</a>
</div>
<p>Compile all expressions within the <strong>Block</strong> body. If we need to return
the result, and its an expression, simply return it. If its a statement,
ask the statement to do so.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@tab = o.indent
top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP
compiledNodes = []
<span class="hljs-keyword">for</span> node, index <span class="hljs-keyword">in</span> @expressions
<span class="hljs-keyword">if</span> node.hoisted</pre></div></div>
</li>
<li id="section-71">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-71">&#x00a7;</a>
</div>
<p>This is a hoisted expression.
We want to compile this and ignore the result.</p>
</div>
<div class="content"><div class='highlight'><pre> node.compileToFragments o
<span class="hljs-keyword">continue</span>
node = (node.unfoldSoak(o) <span class="hljs-keyword">or</span> node)
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Block</pre></div></div>
</li>
<li id="section-72">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-72">&#x00a7;</a>
</div>
<p>This is a nested block. We dont do anything special here like
enclose it in a new scope; we just compile the statements in this
block along with our own.</p>
</div>
<div class="content"><div class='highlight'><pre> compiledNodes.push node.compileNode o
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> top
node.front = <span class="hljs-literal">yes</span>
fragments = node.compileToFragments o
<span class="hljs-keyword">unless</span> node.isStatement o
fragments = indentInitial fragments, @
[..., lastFragment] = fragments
<span class="hljs-keyword">unless</span> lastFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">or</span> lastFragment.isComment
fragments.push @makeCode <span class="hljs-string">&#x27;;&#x27;</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">&#x27;\n\n&#x27;</span>), @makeCode(<span class="hljs-string">&#x27;\n&#x27;</span>)
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> @joinFragmentArrays(compiledNodes, <span class="hljs-string">&#x27;\n&#x27;</span>)
<span class="hljs-keyword">if</span> compiledNodes.length
answer = @joinFragmentArrays(compiledNodes, <span class="hljs-string">&#x27;, &#x27;</span>)
<span class="hljs-keyword">else</span>
answer = [@makeCode <span class="hljs-string">&#x27;void 0&#x27;</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
compileRoot: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@spaced = <span class="hljs-literal">yes</span>
fragments = @compileWithDeclarations o
HoistTarget.expand fragments
@compileComments fragments</pre></div></div>
</li>
<li id="section-73">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-73">&#x00a7;</a>
</div>
<p>Compile the expressions body for the contents of a function, with
declarations of all inner variables pushed up to the top.</p>
</div>
<div class="content"><div class='highlight'><pre> compileWithDeclarations: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragments = []
post = []
<span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> @expressions
exp = exp.unwrap()
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp <span class="hljs-keyword">instanceof</span> Literal
o = merge(o, level: LEVEL_TOP)
<span class="hljs-keyword">if</span> i
rest = @expressions.splice i, <span class="hljs-number">9e9</span>
[spaced, @spaced] = [@spaced, <span class="hljs-literal">no</span>]
[fragments, @spaced] = [@compileNode(o), spaced]
@expressions = rest
post = @compileNode o
{scope} = o
<span class="hljs-keyword">if</span> scope.expressions <span class="hljs-keyword">is</span> this
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">&#x27;\n&#x27;</span> <span class="hljs-keyword">if</span> i
fragments.push @makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>var &quot;</span>
<span class="hljs-keyword">if</span> declars
declaredVariables = scope.declaredVariables()
<span class="hljs-keyword">for</span> declaredVariable, declaredVariablesIndex <span class="hljs-keyword">in</span> declaredVariables
fragments.push @makeCode declaredVariable
<span class="hljs-keyword">if</span> Object::hasOwnProperty.call o.scope.comments, declaredVariable
fragments.push o.scope.comments[declaredVariable]...
<span class="hljs-keyword">if</span> declaredVariablesIndex <span class="hljs-keyword">isnt</span> declaredVariables.length - <span class="hljs-number">1</span>
fragments.push @makeCode <span class="hljs-string">&#x27;, &#x27;</span>
<span class="hljs-keyword">if</span> assigns
fragments.push @makeCode <span class="hljs-string">&quot;,\n<span class="hljs-subst">#{@tab + TAB}</span>&quot;</span> <span class="hljs-keyword">if</span> declars
fragments.push @makeCode scope.assignedVariables().join(<span class="hljs-string">&quot;,\n<span class="hljs-subst">#{@tab + TAB}</span>&quot;</span>)
fragments.push @makeCode <span class="hljs-string">&quot;;\n<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @spaced <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>&quot;</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">&quot;\n&quot;</span>
fragments.concat post
compileComments: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments</pre></div></div>
</li>
<li id="section-74">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-74">&#x00a7;</a>
</div>
<p>Insert comments into the output at the next or previous newline.
If there are no newlines at which to place comments, create them.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.precedingComments</pre></div></div>
</li>
<li id="section-75">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-75">&#x00a7;</a>
</div>
<p>Determine the indentation level of the fragment that we are about
to insert comments before, and use that indentation level for our
inserted comments. At this point, the fragments <code>code</code> property
is the generated output JavaScript, and CoffeeScript always
generates output indented by two spaces; so all we need to do is
search for a <code>code</code> property that begins with at least two spaces.</p>
</div>
<div class="content"><div class='highlight'><pre> fragmentIndent = <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">for</span> pastFragment <span class="hljs-keyword">in</span> fragments[<span class="hljs-number">0.</span>..(fragmentIndex + <span class="hljs-number">1</span>)] <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
indent = <span class="hljs-regexp">/^ {2,}/m</span>.exec pastFragment.code
<span class="hljs-keyword">if</span> indent
fragmentIndent = indent[<span class="hljs-number">0</span>]
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> pastFragment.code
<span class="hljs-keyword">break</span>
code = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{fragmentIndent}</span>&quot;</span> + (
<span class="hljs-keyword">for</span> commentFragment <span class="hljs-keyword">in</span> fragment.precedingComments
<span class="hljs-keyword">if</span> commentFragment.isHereComment <span class="hljs-keyword">and</span> commentFragment.multiline
multident commentFragment.code, fragmentIndent, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
commentFragment.code
).join(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{fragmentIndent}</span>&quot;</span>).replace <span class="hljs-regexp">/^(\s*)$/gm</span>, <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">for</span> pastFragment, pastFragmentIndex <span class="hljs-keyword">in</span> fragments[<span class="hljs-number">0.</span>..(fragmentIndex + <span class="hljs-number">1</span>)] <span class="hljs-keyword">by</span> <span class="hljs-number">-1</span>
newLineIndex = pastFragment.code.lastIndexOf <span class="hljs-string">&#x27;\n&#x27;</span>
<span class="hljs-keyword">if</span> newLineIndex <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span></pre></div></div>
</li>
<li id="section-76">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-76">&#x00a7;</a>
</div>
<p>Keep searching previous fragments until we cant go back any
further, either because there are no fragments left or weve
discovered that were in a code block that is interpolated
inside a string.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> pastFragmentIndex <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
pastFragment.code = <span class="hljs-string">&#x27;\n&#x27;</span> + pastFragment.code
newLineIndex = <span class="hljs-number">0</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> pastFragment.isStringWithInterpolations <span class="hljs-keyword">and</span> pastFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;{&#x27;</span>
code = code[<span class="hljs-number">1.</span>.] + <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-comment"># Move newline to end.</span>
newLineIndex = <span class="hljs-number">1</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">delete</span> fragment.precedingComments
pastFragment.code = pastFragment.code[<span class="hljs-number">0.</span>..newLineIndex] +
code + pastFragment.code[newLineIndex..]
<span class="hljs-keyword">break</span></pre></div></div>
</li>
<li id="section-77">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-77">&#x00a7;</a>
</div>
<p>Yes, this is awfully similar to the previous <code>if</code> block, but if you
look closely youll find lots of tiny differences that make this
confusing if it were abstracted into a function that both blocks share.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> fragment.followingComments</pre></div></div>
</li>
<li id="section-78">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-78">&#x00a7;</a>
</div>
<p>Does the first trailing comment follow at the end of a line of code,
like <code>; // Comment</code>, or does it start a new line after a line of code?</p>
</div>
<div class="content"><div class='highlight'><pre> trail = fragment.followingComments[<span class="hljs-number">0</span>].trail
fragmentIndent = <span class="hljs-string">&#x27;&#x27;</span></pre></div></div>
</li>
<li id="section-79">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-79">&#x00a7;</a>
</div>
<p>Find the indent of the next line of code, if we have any non-trailing
comments to output. We need to first find the next newline, as these
comments will be output after that; and then the indent of the line
that follows the next newline.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> trail <span class="hljs-keyword">and</span> fragment.followingComments.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
onNextLine = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> upcomingFragment <span class="hljs-keyword">in</span> fragments[fragmentIndex...]
<span class="hljs-keyword">unless</span> onNextLine
<span class="hljs-keyword">if</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> upcomingFragment.code
onNextLine = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">else</span>
indent = <span class="hljs-regexp">/^ {2,}/m</span>.exec upcomingFragment.code
<span class="hljs-keyword">if</span> indent
fragmentIndent = indent[<span class="hljs-number">0</span>]
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> upcomingFragment.code
<span class="hljs-keyword">break</span></pre></div></div>
</li>
<li id="section-80">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-80">&#x00a7;</a>
</div>
<p>Is this comment following the indent inserted by bare mode?
If so, theres no need to indent this further.</p>
</div>
<div class="content"><div class='highlight'><pre> code = <span class="hljs-keyword">if</span> fragmentIndex <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-regexp">/^\s+$/</span>.test fragments[<span class="hljs-number">0</span>].code
<span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> trail
<span class="hljs-string">&#x27; &#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;\n<span class="hljs-subst">#{fragmentIndent}</span>&quot;</span></pre></div></div>
</li>
<li id="section-81">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-81">&#x00a7;</a>
</div>
<p>Assemble properly indented comments.</p>
</div>
<div class="content"><div class='highlight'><pre> code += (
<span class="hljs-keyword">for</span> commentFragment <span class="hljs-keyword">in</span> fragment.followingComments
<span class="hljs-keyword">if</span> commentFragment.isHereComment <span class="hljs-keyword">and</span> commentFragment.multiline
multident commentFragment.code, fragmentIndent, <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
commentFragment.code
).join(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{fragmentIndent}</span>&quot;</span>).replace <span class="hljs-regexp">/^(\s*)$/gm</span>, <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">for</span> upcomingFragment, upcomingFragmentIndex <span class="hljs-keyword">in</span> fragments[fragmentIndex...]
newLineIndex = upcomingFragment.code.indexOf <span class="hljs-string">&#x27;\n&#x27;</span>
<span class="hljs-keyword">if</span> newLineIndex <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span></pre></div></div>
</li>
<li id="section-82">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-82">&#x00a7;</a>
</div>
<p>Keep searching upcoming fragments until we cant go any
further, either because there are no fragments left or weve
discovered that were in a code block that is interpolated
inside a string.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> upcomingFragmentIndex <span class="hljs-keyword">is</span> fragments.length - <span class="hljs-number">1</span>
upcomingFragment.code = upcomingFragment.code + <span class="hljs-string">&#x27;\n&#x27;</span>
newLineIndex = upcomingFragment.code.length
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> upcomingFragment.isStringWithInterpolations <span class="hljs-keyword">and</span> upcomingFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;}&#x27;</span>
code = <span class="hljs-string">&quot;<span class="hljs-subst">#{code}</span>\n&quot;</span>
newLineIndex = <span class="hljs-number">0</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">delete</span> fragment.followingComments</pre></div></div>
</li>
<li id="section-83">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-83">&#x00a7;</a>
</div>
<p>Avoid inserting extra blank lines.</p>
</div>
<div class="content"><div class='highlight'><pre> code = code.replace <span class="hljs-regexp">/^\n/</span>, <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">if</span> upcomingFragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;\n&#x27;</span>
upcomingFragment.code = upcomingFragment.code[<span class="hljs-number">0.</span>..newLineIndex] +
code + upcomingFragment.code[newLineIndex..]
<span class="hljs-keyword">break</span>
fragments</pre></div></div>
</li>
<li id="section-84">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-84">&#x00a7;</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
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> (o.level? <span class="hljs-keyword">and</span> o.level <span class="hljs-keyword">isnt</span> LEVEL_TOP) <span class="hljs-keyword">and</span> @expressions.length
<span class="hljs-keyword">return</span> (<span class="hljs-keyword">new</span> Sequence(@expressions).withLocationDataFrom @).ast o
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isRootBlock
<span class="hljs-string">&#x27;Program&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @isClassBody
<span class="hljs-string">&#x27;ClassBody&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;BlockStatement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
checkForDirectives = del o, <span class="hljs-string">&#x27;checkForDirectives&#x27;</span>
sniffDirectives @expressions, notFinalExpression: checkForDirectives <span class="hljs-keyword">if</span> @isRootBlock <span class="hljs-keyword">or</span> checkForDirectives
directives = []
body = []
<span class="hljs-keyword">for</span> expression <span class="hljs-keyword">in</span> @expressions
expressionAst = expression.ast o</pre></div></div>
</li>
<li id="section-85">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-85">&#x00a7;</a>
</div>
<p>Ignore generated PassthroughLiteral</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expressionAst?
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> expression <span class="hljs-keyword">instanceof</span> Directive
directives.push expressionAst</pre></div></div>
</li>
<li id="section-86">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-86">&#x00a7;</a>
</div>
<p>If an expression is a statement, it can be added to the body as is.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> expression.isStatementAst o
body.push expressionAst</pre></div></div>
</li>
<li id="section-87">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-87">&#x00a7;</a>
</div>
<p>Otherwise, we need to wrap it in an <code>ExpressionStatement</code> AST node.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span>
body.push <span class="hljs-built_in">Object</span>.assign
type: <span class="hljs-string">&#x27;ExpressionStatement&#x27;</span>
expression: expressionAst
,
expression.astLocationData()
<span class="hljs-keyword">return</span> {</pre></div></div>
</li>
<li id="section-88">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-88">&#x00a7;</a>
</div>
<p>For now, were not including <code>sourceType</code> on the <code>Program</code> AST node.
Its value could be either <code>&#39;script&#39;</code> or <code>&#39;module&#39;</code>, and theres no way
for CoffeeScript to always know which it should be. The presence of an
<code>import</code> or <code>export</code> statement in source code would imply that it should
be a <code>module</code>, but a project may consist of mostly such files and also
an outlier file that lacks <code>import</code> or <code>export</code> but is still imported
into the project and therefore expects to be treated as a <code>module</code>.
Determining the value of <code>sourceType</code> is essentially the same challenge
posed by determining the parse goal of a JavaScript file, also <code>module</code>
or <code>script</code>, and so if Node figures out a way to do so for <code>.js</code> files
then CoffeeScript can copy Nodes algorithm.</p>
</div>
</li>
<li id="section-89">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-89">&#x00a7;</a>
</div>
<p>sourceType: module</p>
</div>
<div class="content"><div class='highlight'><pre> body, directives
}
astLocationData: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> @isRootBlock <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @locationData?
super()</pre></div></div>
</li>
<li id="section-90">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-90">&#x00a7;</a>
</div>
<p>A directive e.g. use strict.
Currently only used during AST generation.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Directive = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Directive</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>
super()
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
value: <span class="hljs-built_in">Object</span>.assign {},
@value.ast o
type: <span class="hljs-string">&#x27;DirectiveLiteral&#x27;</span></pre></div></div>
</li>
<li id="section-91">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-91">&#x00a7;</a>
</div>
<h3 id="literal">Literal</h3>
</div>
</li>
<li id="section-92">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-92">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
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]
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value: @value
toString: <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-93">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-93">&#x00a7;</a>
</div>
<p>This is only intended for debugging.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-string">&quot; <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isStatement() <span class="hljs-keyword">then</span> super() <span class="hljs-keyword">else</span> @constructor.name}</span>: <span class="hljs-subst">#{@value}</span>&quot;</span>
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(@value, {@parsedValue} = {})</span> -&gt;</span>
super()
<span class="hljs-keyword">unless</span> @parsedValue?
<span class="hljs-keyword">if</span> isNumber @value
@parsedValue = @value
@value = <span class="hljs-string">&quot;<span class="hljs-subst">#{@value}</span>&quot;</span>
<span class="hljs-keyword">else</span>
@parsedValue = parseNumber @value
isBigInt: <span class="hljs-function">-&gt;</span>
<span class="hljs-regexp">/n$/</span>.test @value
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isBigInt()
<span class="hljs-string">&#x27;BigIntLiteral&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;NumericLiteral&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value:
<span class="hljs-keyword">if</span> @isBigInt()
@parsedValue.toString()
<span class="hljs-keyword">else</span>
@parsedValue
extra:
rawValue:
<span class="hljs-keyword">if</span> @isBigInt()
@parsedValue.toString()
<span class="hljs-keyword">else</span>
@parsedValue
raw: @value
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(@value, {@originalValue = <span class="hljs-string">&#x27;Infinity&#x27;</span>} = {})</span> -&gt;</span>
super()
compileNode: <span class="hljs-function">-&gt;</span>
[@makeCode <span class="hljs-string">&#x27;2e308&#x27;</span>]
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> @originalValue <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;Infinity&#x27;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NumberLiteral(@value).withLocationDataFrom(@).ast o
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: <span class="hljs-string">&#x27;Infinity&#x27;</span>
declaration: <span class="hljs-literal">no</span>
<span class="hljs-built_in">exports</span>.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>
super <span class="hljs-string">&#x27;NaN&#x27;</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = [@makeCode <span class="hljs-string">&#x27;0/0&#x27;</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
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: <span class="hljs-string">&#x27;NaN&#x27;</span>
declaration: <span class="hljs-literal">no</span>
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(@originalValue, {@quote, @initialChunk, @finalChunk, @indent, @double, @heregex} = {})</span> -&gt;</span>
super <span class="hljs-string">&#x27;&#x27;</span>
@quote = <span class="hljs-literal">null</span> <span class="hljs-keyword">if</span> @quote <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;///&#x27;</span>
@fromSourceString = @quote?
@quote ?= <span class="hljs-string">&#x27;&quot;&#x27;</span>
heredoc = @isFromHeredoc()
val = @originalValue
<span class="hljs-keyword">if</span> @heregex
val = val.replace HEREGEX_OMIT, <span class="hljs-string">&#x27;$1$2&#x27;</span>
val = replaceUnicodeCodePointEscapes val, flags: @heregex.flags
<span class="hljs-keyword">else</span>
val = val.replace STRING_OMIT, <span class="hljs-string">&#x27;$1&#x27;</span>
val =
<span class="hljs-keyword">unless</span> @fromSourceString
val
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> heredoc
indentRegex = <span class="hljs-regexp">/// \n<span class="hljs-subst">#{@indent}</span> ///</span>g <span class="hljs-keyword">if</span> @indent
val = val.replace indentRegex, <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">if</span> indentRegex
val = val.replace LEADING_BLANK_LINE, <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">if</span> @initialChunk
val = val.replace TRAILING_BLANK_LINE, <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">if</span> @finalChunk
val
<span class="hljs-keyword">else</span>
val.replace SIMPLE_STRING_OMIT, <span class="hljs-function"><span class="hljs-params">(match, offset)</span> =&gt;</span>
<span class="hljs-keyword">if</span> (@initialChunk <span class="hljs-keyword">and</span> offset <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>) <span class="hljs-keyword">or</span>
(@finalChunk <span class="hljs-keyword">and</span> offset + match.length <span class="hljs-keyword">is</span> val.length)
<span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27; &#x27;</span>
@delimiter = @quote.charAt <span class="hljs-number">0</span>
@value = makeDelimitedLiteral val, {
@delimiter
@double
}
@unquotedValueForTemplateLiteral = makeDelimitedLiteral val, {
delimiter: <span class="hljs-string">&#x27;`&#x27;</span>
@double
escapeNewlines: <span class="hljs-literal">no</span>
includeDelimiters: <span class="hljs-literal">no</span>
convertTrailingNullEscapes: <span class="hljs-literal">yes</span>
}
@unquotedValueForJSX = makeDelimitedLiteral val, {
@double
escapeNewlines: <span class="hljs-literal">no</span>
includeDelimiters: <span class="hljs-literal">no</span>
escapeDelimiter: <span class="hljs-literal">no</span>
}
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> StringWithInterpolations.fromStringLiteral(@).compileNode o <span class="hljs-keyword">if</span> @shouldGenerateTemplateLiteral()
<span class="hljs-keyword">return</span> [@makeCode @unquotedValueForJSX] <span class="hljs-keyword">if</span> @jsx
super o</pre></div></div>
</li>
<li id="section-94">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-94">&#x00a7;</a>
</div>
<p><code>StringLiteral</code>s can represent either entire literal strings
or pieces of text inside of e.g. an interpolated string.
When parsed as the former but needing to be treated as the latter
(e.g. the string part of a tagged template literal), this will return
a copy of the <code>StringLiteral</code> with the quotes trimmed from its location
data (like it would have if parsed as part of an interpolated string).</p>
</div>
<div class="content"><div class='highlight'><pre> withoutQuotesInLocationData: <span class="hljs-function">-&gt;</span>
endsWithNewline = @originalValue[<span class="hljs-number">-1.</span>.] <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;\n&#x27;</span>
locationData = <span class="hljs-built_in">Object</span>.assign {}, @locationData
locationData.first_column += @quote.length
<span class="hljs-keyword">if</span> endsWithNewline
locationData.last_line -= <span class="hljs-number">1</span>
locationData.last_column =
<span class="hljs-keyword">if</span> locationData.last_line <span class="hljs-keyword">is</span> locationData.first_line
locationData.first_column + @originalValue.length - <span class="hljs-string">&#x27;\n&#x27;</span>.length
<span class="hljs-keyword">else</span>
@originalValue[...<span class="hljs-number">-1</span>].length - <span class="hljs-string">&#x27;\n&#x27;</span>.length - @originalValue[...<span class="hljs-number">-1</span>].lastIndexOf(<span class="hljs-string">&#x27;\n&#x27;</span>)
<span class="hljs-keyword">else</span>
locationData.last_column -= @quote.length
locationData.last_column_exclusive -= @quote.length
locationData.range = [
locationData.range[<span class="hljs-number">0</span>] + @quote.length
locationData.range[<span class="hljs-number">1</span>] - @quote.length
]
copy = <span class="hljs-keyword">new</span> StringLiteral @originalValue, {@quote, @initialChunk, @finalChunk, @indent, @double, @heregex}
copy.locationData = locationData
copy
isFromHeredoc: <span class="hljs-function">-&gt;</span>
@quote.length <span class="hljs-keyword">is</span> <span class="hljs-number">3</span>
shouldGenerateTemplateLiteral: <span class="hljs-function">-&gt;</span>
@isFromHeredoc()
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> StringWithInterpolations.fromStringLiteral(@).ast o <span class="hljs-keyword">if</span> @shouldGenerateTemplateLiteral()
super o
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value: @originalValue
extra:
raw: <span class="hljs-string">&quot;<span class="hljs-subst">#{@delimiter}</span><span class="hljs-subst">#{@originalValue}</span><span class="hljs-subst">#{@delimiter}</span>&quot;</span>
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(value, {@delimiter = <span class="hljs-string">&#x27;/&#x27;</span>, @heregexCommentTokens = []} = {})</span> -&gt;</span>
super <span class="hljs-string">&#x27;&#x27;</span>
heregex = @delimiter <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;///&#x27;</span>
endDelimiterIndex = value.lastIndexOf <span class="hljs-string">&#x27;/&#x27;</span>
@flags = value[endDelimiterIndex + <span class="hljs-number">1.</span>.]
val = @originalValue = value[<span class="hljs-number">1.</span>..endDelimiterIndex]
val = val.replace HEREGEX_OMIT, <span class="hljs-string">&#x27;$1$2&#x27;</span> <span class="hljs-keyword">if</span> heregex
val = replaceUnicodeCodePointEscapes val, {@flags}
@value = <span class="hljs-string">&quot;<span class="hljs-subst">#{makeDelimitedLiteral val, delimiter: <span class="hljs-string">&#x27;/&#x27;</span>}</span><span class="hljs-subst">#{@flags}</span>&quot;</span>
REGEX_REGEX: <span class="hljs-regexp">/// ^ / (.*) / \w* $ ///</span>
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;RegExpLiteral&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[, pattern] = @REGEX_REGEX.exec @value
<span class="hljs-keyword">return</span> {
value: <span class="hljs-literal">undefined</span>
pattern, @flags, @delimiter
originalPattern: @originalValue
extra:
raw: @value
originalRaw: <span class="hljs-string">&quot;<span class="hljs-subst">#{@delimiter}</span><span class="hljs-subst">#{@originalValue}</span><span class="hljs-subst">#{@delimiter}</span><span class="hljs-subst">#{@flags}</span>&quot;</span>
rawValue: <span class="hljs-literal">undefined</span>
comments:
<span class="hljs-keyword">for</span> heregexCommentToken <span class="hljs-keyword">in</span> @heregexCommentTokens
<span class="hljs-keyword">if</span> heregexCommentToken.here
<span class="hljs-keyword">new</span> HereComment(heregexCommentToken).ast o
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> LineComment(heregexCommentToken).ast o
}
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(@originalValue, {@here, @generated} = {})</span> -&gt;</span>
super <span class="hljs-string">&#x27;&#x27;</span>
@value = @originalValue.replace <span class="hljs-regexp">/\\+(`|$)/g</span>, <span class="hljs-function"><span class="hljs-params">(string)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-95">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-95">&#x00a7;</a>
</div>
<p><code>string</code> is always a value like `, \`, \\`, etc.
By reducing it to its latter half, we turn ` to <code>&#39;, &#39;\\\</code> to `, etc.</p>
</div>
<div class="content"><div class='highlight'><pre> string[-<span class="hljs-built_in">Math</span>.ceil(string.length / <span class="hljs-number">2</span>)..]
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">if</span> @generated
super o
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> {
value: @originalValue
here: !!@here
}
<span class="hljs-built_in">exports</span>.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 @
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @jsx
<span class="hljs-string">&#x27;JSXIdentifier&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: @value
declaration: !!@isDeclaration
<span class="hljs-built_in">exports</span>.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
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @jsx
<span class="hljs-string">&#x27;JSXIdentifier&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: @value
declaration: <span class="hljs-literal">no</span>
<span class="hljs-built_in">exports</span>.ComputedPropertyName = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ComputedPropertyName</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">PropertyName</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode(<span class="hljs-string">&#x27;[&#x27;</span>), @value.compileToFragments(o, LEVEL_LIST)..., @makeCode(<span class="hljs-string">&#x27;]&#x27;</span>)]
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@value.ast o
<span class="hljs-built_in">exports</span>.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> this <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;break&#x27;</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> this <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;continue&#x27;</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">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{@value}</span>;&quot;</span>]
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">switch</span> @value
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;continue&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;ContinueStatement&#x27;</span>
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;break&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;BreakStatement&#x27;</span>
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;debugger&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;DebuggerStatement&#x27;</span>
<span class="hljs-built_in">exports</span>.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"><span class="hljs-params">(value)</span> -&gt;</span>
super <span class="hljs-string">&#x27;this&#x27;</span>
@shorthand = value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;@&#x27;</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]
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;ThisExpression&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
shorthand: @shorthand
<span class="hljs-built_in">exports</span>.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>
super <span class="hljs-string">&#x27;undefined&#x27;</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">&#x27;(void 0)&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;void 0&#x27;</span>]
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: @value
declaration: <span class="hljs-literal">no</span>
<span class="hljs-built_in">exports</span>.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>
super <span class="hljs-string">&#x27;null&#x27;</span>
<span class="hljs-built_in">exports</span>.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>
constructor: <span class="hljs-function"><span class="hljs-params">(value, {@originalValue} = {})</span> -&gt;</span>
super value
@originalValue ?= @value
astProperties: <span class="hljs-function">-&gt;</span>
value: <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;true&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">else</span> <span class="hljs-literal">no</span>
name: @originalValue
<span class="hljs-built_in">exports</span>.DefaultLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DefaultLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;Identifier&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: <span class="hljs-string">&#x27;default&#x27;</span>
declaration: <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-96">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-96">&#x00a7;</a>
</div>
<h3 id="return">Return</h3>
</div>
</li>
<li id="section-97">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-97">&#x00a7;</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><span class="hljs-built_in">exports</span>.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, {@belongsToFuncDirectiveReturn} = {})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;expression&#x27;</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> super o, level
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
answer = []</pre></div></div>
</li>
<li id="section-98">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-98">&#x00a7;</a>
</div>
<p>TODO: If we call <code>expression.compile()</code> here twice, well sometimes
get back different results!</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @expression
answer = @expression.compileToFragments o, LEVEL_PAREN
unshiftAfterComments answer, @makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>return &quot;</span></pre></div></div>
</li>
<li id="section-99">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-99">&#x00a7;</a>
</div>
<p>Since the <code>return</code> got indented by <code>@tab</code>, preceding comments that are
multiline need to be indented.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> answer
<span class="hljs-keyword">if</span> fragment.isHereComment <span class="hljs-keyword">and</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> fragment.code
fragment.code = multident fragment.code, @tab
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.isLineComment
fragment.code = <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{fragment.code}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">else</span>
answer.push @makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>return&quot;</span>
answer.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
answer
checkForPureStatementInExpression: <span class="hljs-function">-&gt;</span></pre></div></div>
</li>
<li id="section-100">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-100">&#x00a7;</a>
</div>
<p>dont flag <code>return</code> from <code>await return</code>/<code>yield return</code> as invalid.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> @belongsToFuncDirectiveReturn
super()
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;ReturnStatement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
argument: @expression?.ast(o, LEVEL_PAREN) ? <span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-101">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-101">&#x00a7;</a>
</div>
<p>Parent class for <code>YieldReturn</code>/<code>AwaitReturn</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.FuncDirectiveReturn = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FuncDirectiveReturn</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Return</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(expression, {@returnKeyword})</span> -&gt;</span>
super expression
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o
super o
checkScope: <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">&quot;<span class="hljs-subst">#{@keyword}</span> can only occur inside functions&quot;</span>
isStatementAst: NO
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o
<span class="hljs-keyword">new</span> Op @keyword,
<span class="hljs-keyword">new</span> Return @expression, belongsToFuncDirectiveReturn: <span class="hljs-literal">yes</span>
.withLocationDataFrom(
<span class="hljs-keyword">if</span> @expression?
locationData: mergeLocationData @returnKeyword.locationData, @expression.locationData
<span class="hljs-keyword">else</span>
@returnKeyword
)
.withLocationDataFrom @
.ast o</pre></div></div>
</li>
<li id="section-102">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-102">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">FuncDirectiveReturn</span></span>
keyword: <span class="hljs-string">&#x27;yield&#x27;</span>
<span class="hljs-built_in">exports</span>.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">FuncDirectiveReturn</span></span>
keyword: <span class="hljs-string">&#x27;await&#x27;</span></pre></div></div>
</li>
<li id="section-103">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-103">&#x00a7;</a>
</div>
<h3 id="value">Value</h3>
</div>
</li>
<li id="section-104">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-104">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
<span class="hljs-keyword">return</span> base <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> props <span class="hljs-keyword">and</span> base <span class="hljs-keyword">instanceof</span> Value
@base = base
@properties = props <span class="hljs-keyword">or</span> []
@tag = tag
@[tag] = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> tag
@isDefaultValue = isDefaultValue</pre></div></div>
</li>
<li id="section-105">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-105">&#x00a7;</a>
</div>
<p>If this is a <code>@foo =</code> assignment, if there are comments on <code>@</code> move them
to be on <code>foo</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @base?.comments <span class="hljs-keyword">and</span> @base <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">and</span> @properties[<span class="hljs-number">0</span>]?.name?
moveComments @base, @properties[<span class="hljs-number">0</span>].name
children: [<span class="hljs-string">&#x27;base&#x27;</span>, <span class="hljs-string">&#x27;properties&#x27;</span>]</pre></div></div>
</li>
<li id="section-106">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-106">&#x00a7;</a>
</div>
<p>Add a property (or <em>properties</em> ) <code>Access</code> to the list.</p>
</div>
<div class="content"><div class='highlight'><pre> add: <span class="hljs-function"><span class="hljs-params">(props)</span> -&gt;</span>
@properties = @properties.concat props
@forceUpdateLocation = <span class="hljs-literal">yes</span>
this
hasProperties: <span class="hljs-function">-&gt;</span>
@properties.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
bareLiteral: <span class="hljs-function"><span class="hljs-params">(type)</span> -&gt;</span>
<span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base <span class="hljs-keyword">instanceof</span> type</pre></div></div>
</li>
<li id="section-107">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-107">&#x00a7;</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"><span class="hljs-params">(opts)</span> -&gt;</span> @hasProperties() <span class="hljs-keyword">or</span> @base.isAssignable opts
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-keyword">or</span> node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;do&#x27;</span>
<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
isJSXTag : <span class="hljs-function">-&gt;</span> @base <span class="hljs-keyword">instanceof</span> JSXTag
assigns : <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.assigns name
jumps : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.jumps o
isObject: <span class="hljs-function"><span class="hljs-params">(onlyGenerated)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> @properties.length
(@base <span class="hljs-keyword">instanceof</span> Obj) <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> onlyGenerated <span class="hljs-keyword">or</span> @base.generated)
isElision: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @base <span class="hljs-keyword">instanceof</span> Arr
@base.hasElision()
isSplice: <span class="hljs-function">-&gt;</span>
[..., lastProperty] = @properties
lastProperty <span class="hljs-keyword">instanceof</span> Slice
looksStatic: <span class="hljs-function"><span class="hljs-params">(className)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> ((thisLiteral = @base) <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">or</span> (name = @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">&#x27;prototype&#x27;</span>
<span class="hljs-keyword">return</span>
staticClassName: thisLiteral ? name</pre></div></div>
</li>
<li id="section-108">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-108">&#x00a7;</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> this <span class="hljs-keyword">else</span> @base</pre></div></div>
</li>
<li id="section-109">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-109">&#x00a7;</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> [this, this] <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">&#x27;base&#x27;</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">&#x27;name&#x27;</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-110">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-110">&#x00a7;</a>
</div>
<p>We compile a value to JavaScript by compiling and joining each property.
Things get much more interesting if the chain of properties has <em>soak</em>
operators <code>?.</code> interspersed. Then we have to take care not to accidentally
evaluate anything twice when building the soak chain.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@base.front = @front
props = @properties
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> @base.cached?</pre></div></div>
</li>
<li id="section-111">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-111">&#x00a7;</a>
</div>
<p>Cached fragments enable correct order of the compilation,
and reuse of variables in the scope.
Example:
<code>a(x = 5).b(-&gt; x = 6)</code> should compile in the same order as
<code>a(x = 5); b(-&gt; x = 6)</code>
(see issue #4437, <a href="https://github.com/jashkenas/coffeescript/issues/4437">https://github.com/jashkenas/coffeescript/issues/4437</a>)</p>
</div>
<div class="content"><div class='highlight'><pre> fragments = @base.cached
<span class="hljs-keyword">else</span>
fragments = @base.compileToFragments o, (<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">then</span> LEVEL_ACCESS <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>)
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> SIMPLENUM.test fragmentsToText fragments
fragments.push @makeCode <span class="hljs-string">&#x27;.&#x27;</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-112">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-112">&#x00a7;</a>
</div>
<p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -&gt; <code>a.b if a?</code></p>
</div>
<div class="content"><div class='highlight'><pre> unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@unfoldedSoak ?= <span class="hljs-keyword">do</span> =&gt;
ifn = @base.unfoldSoak o
<span class="hljs-keyword">if</span> ifn
ifn.body.properties.push @properties...
<span class="hljs-keyword">return</span> ifn
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop.soak
prop.soak = <span class="hljs-literal">off</span>
fst = <span class="hljs-keyword">new</span> Value @base, @properties[...i]
snd = <span class="hljs-keyword">new</span> Value @base, @properties[i..]
<span class="hljs-keyword">if</span> fst.shouldCache()
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">&#x27;ref&#x27;</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, {checkAssignability = <span class="hljs-literal">yes</span>} = {})</span> -&gt;</span>
<span class="hljs-keyword">if</span> @hasProperties()
iterator @
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> checkAssignability <span class="hljs-keyword">or</span> @base.isAssignable()
@base.eachName iterator
<span class="hljs-keyword">else</span>
@error <span class="hljs-string">&#x27;tried to assign to unassignable value&#x27;</span></pre></div></div>
</li>
<li id="section-113">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-113">&#x00a7;</a>
</div>
<p>For AST generation, we need an <code>object</code> thats this <code>Value</code> minus its last
property, if it has properties.</p>
</div>
<div class="content"><div class='highlight'><pre> object: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> @ <span class="hljs-keyword">unless</span> @hasProperties()</pre></div></div>
</li>
<li id="section-114">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-114">&#x00a7;</a>
</div>
<p>Get all properties except the last one; for a <code>Value</code> with only one
property, <code>initialProperties</code> is an empty array.</p>
</div>
<div class="content"><div class='highlight'><pre> initialProperties = @properties[<span class="hljs-number">0.</span>..@properties.length - <span class="hljs-number">1</span>]</pre></div></div>
</li>
<li id="section-115">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-115">&#x00a7;</a>
</div>
<p>Create the <code>object</code> that becomes the new “base” for the split-off final
property.</p>
</div>
<div class="content"><div class='highlight'><pre> object = <span class="hljs-keyword">new</span> Value @base, initialProperties, @tag, @isDefaultValue</pre></div></div>
</li>
<li id="section-116">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-116">&#x00a7;</a>
</div>
<p>Add location data to our new node, so that it has correct location data
for source maps or later conversion into AST location data.</p>
</div>
<div class="content"><div class='highlight'><pre> object.locationData =
<span class="hljs-keyword">if</span> initialProperties.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span></pre></div></div>
</li>
<li id="section-117">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-117">&#x00a7;</a>
</div>
<p>This new <code>Value</code> has only one property, so the location data is just
that of the parent <code>Value</code>s base.</p>
</div>
<div class="content"><div class='highlight'><pre> @base.locationData
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-118">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-118">&#x00a7;</a>
</div>
<p>This new <code>Value</code> has multiple properties, so the location data spans
from the parent <code>Value</code>s base to the last property thats included
in this new node (a.k.a. the second-to-last property of the parent).</p>
</div>
<div class="content"><div class='highlight'><pre> mergeLocationData @base.locationData, initialProperties[initialProperties.length - <span class="hljs-number">1</span>].locationData
object
containsSoak: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> @hasProperties()
<span class="hljs-keyword">for</span> property <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> property.soak
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @base <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> @base.soak
<span class="hljs-literal">no</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-119">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-119">&#x00a7;</a>
</div>
<p>If the <code>Value</code> has no properties, the AST node is just whatever this
nodes <code>base</code> is.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> @base.ast o <span class="hljs-keyword">unless</span> @hasProperties()</pre></div></div>
</li>
<li id="section-120">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-120">&#x00a7;</a>
</div>
<p>Otherwise, call <code>Base::ast</code> which in turn calls the <code>astType</code> and
<code>astProperties</code> methods below.</p>
</div>
<div class="content"><div class='highlight'><pre> super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isJSXTag()
<span class="hljs-string">&#x27;JSXMemberExpression&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @containsSoak()
<span class="hljs-string">&#x27;OptionalMemberExpression&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;MemberExpression&#x27;</span></pre></div></div>
</li>
<li id="section-121">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-121">&#x00a7;</a>
</div>
<p>If this <code>Value</code> has properties, the <em>last</em> property (e.g. <code>c</code> in <code>a.b.c</code>)
becomes the <code>property</code>, and the preceding properties (e.g. <code>a.b</code>) become
a child <code>Value</code> node assigned to the <code>object</code> property.</p>
</div>
<div class="content"><div class='highlight'><pre> astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[..., property] = @properties
property.name.jsx = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @isJSXTag()
computed = property <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">or</span> property.name?.unwrap() <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> PropertyName
<span class="hljs-keyword">return</span> {
object: @object().ast o, LEVEL_ACCESS
property: property.ast o, (LEVEL_PAREN <span class="hljs-keyword">if</span> computed)
computed
optional: !!property.soak
shorthand: !!property.shorthand
}
astLocationData: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> super() <span class="hljs-keyword">unless</span> @isJSXTag()</pre></div></div>
</li>
<li id="section-122">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-122">&#x00a7;</a>
</div>
<p>dont include leading &lt; of JSX tag in location data</p>
</div>
<div class="content"><div class='highlight'><pre> mergeAstLocationData(
jisonLocationDataToAstLocationData(@base.tagNameLocationData),
jisonLocationDataToAstLocationData(@properties[@properties.length - <span class="hljs-number">1</span>].locationData)
)
<span class="hljs-built_in">exports</span>.MetaProperty = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MetaProperty</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@meta, @property)</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;meta&#x27;</span>, <span class="hljs-string">&#x27;property&#x27;</span>]
checkValid: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @meta.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;new&#x27;</span>
<span class="hljs-keyword">if</span> @property <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> @property.name.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;target&#x27;</span>
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">&quot;new.target can only occur inside functions&quot;</span>
<span class="hljs-keyword">else</span>
@error <span class="hljs-string">&quot;the only valid meta property for new is new.target&quot;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @meta.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;import&#x27;</span>
<span class="hljs-keyword">unless</span> @property <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> @property.name.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;meta&#x27;</span>
@error <span class="hljs-string">&quot;the only valid meta property for import is import.meta&quot;</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkValid o
fragments = []
fragments.push @meta.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @property.compileToFragments(o)...
fragments
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkValid o
<span class="hljs-keyword">return</span>
meta: @meta.ast o, LEVEL_ACCESS
property: @property.ast o</pre></div></div>
</li>
<li id="section-123">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-123">&#x00a7;</a>
</div>
<h3 id="herecomment">HereComment</h3>
</div>
</li>
<li id="section-124">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-124">&#x00a7;</a>
</div>
<p>Comment delimited by <code>###</code> (becoming <code>/* */</code>).</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.HereComment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HereComment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({ @content, @newLine, @unshift, @locationData })</span> -&gt;</span>
super()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
multiline = <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> @content</pre></div></div>
</li>
<li id="section-125">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-125">&#x00a7;</a>
</div>
<p>Unindent multiline comments. They will be reindented later.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> multiline
indent = <span class="hljs-literal">null</span>
<span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> @content.split <span class="hljs-string">&#x27;\n&#x27;</span>
leadingWhitespace = <span class="hljs-regexp">/^\s*/</span>.exec(line)[<span class="hljs-number">0</span>]
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> indent <span class="hljs-keyword">or</span> leadingWhitespace.length &lt; indent.length
indent = leadingWhitespace
@content = @content.replace <span class="hljs-regexp">/// \n <span class="hljs-subst">#{indent}</span> ///</span>g, <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">if</span> indent
hasLeadingMarks = <span class="hljs-regexp">/\n\s*[#|\*]/</span>.test @content
@content = @content.replace <span class="hljs-regexp">/^([ \t]*)#(?=\s)/gm</span>, <span class="hljs-string">&#x27; *&#x27;</span> <span class="hljs-keyword">if</span> hasLeadingMarks
@content = <span class="hljs-string">&quot;/*<span class="hljs-subst">#{@content}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> hasLeadingMarks <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>*/&quot;</span>
fragment = @makeCode @content
fragment.newLine = @newLine
fragment.unshift = @unshift
fragment.multiline = multiline</pre></div></div>
</li>
<li id="section-126">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-126">&#x00a7;</a>
</div>
<p>Dont rely on <code>fragment.type</code>, which can break when the compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> fragment.isComment = fragment.isHereComment = <span class="hljs-literal">yes</span>
fragment
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;CommentBlock&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value: @content</pre></div></div>
</li>
<li id="section-127">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-127">&#x00a7;</a>
</div>
<h3 id="linecomment">LineComment</h3>
</div>
</li>
<li id="section-128">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-128">&#x00a7;</a>
</div>
<p>Comment running from <code>#</code> to the end of a line (becoming <code>//</code>).</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.LineComment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LineComment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({ @content, @newLine, @unshift, @locationData, @precededByBlankLine })</span> -&gt;</span>
super()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragment = @makeCode(<span class="hljs-keyword">if</span> <span class="hljs-regexp">/^\s*$/</span>.test @content <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @precededByBlankLine <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;\n<span class="hljs-subst">#{o.indent}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>//<span class="hljs-subst">#{@content}</span>&quot;</span>)
fragment.newLine = @newLine
fragment.unshift = @unshift
fragment.trail = <span class="hljs-keyword">not</span> @newLine <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @unshift</pre></div></div>
</li>
<li id="section-129">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-129">&#x00a7;</a>
</div>
<p>Dont rely on <code>fragment.type</code>, which can break when the compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> fragment.isComment = fragment.isLineComment = <span class="hljs-literal">yes</span>
fragment
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;CommentLine&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value: @content</pre></div></div>
</li>
<li id="section-130">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-130">&#x00a7;</a>
</div>
<h3 id="jsx">JSX</h3>
</div>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.JSXIdentifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXIdentifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">IdentifierLiteral</span></span>
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;JSXIdentifier&#x27;</span>
<span class="hljs-built_in">exports</span>.JSXTag = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXTag</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JSXIdentifier</span></span>
constructor: (value, {
@tagNameLocationData
@closingTagOpeningBracketLocationData
@closingTagSlashLocationData
@closingTagNameLocationData
@closingTagClosingBracketLocationData
}) -&gt;
super value
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
name: @value
<span class="hljs-built_in">exports</span>.JSXExpressionContainer = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXExpressionContainer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression, {locationData} = {})</span> -&gt;</span>
super()
@expression.jsxAttribute = <span class="hljs-literal">yes</span>
@locationData = locationData ? @expression.locationData
children: [<span class="hljs-string">&#x27;expression&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@expression.compileNode(o)
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
expression: astAsBlockIfNeeded @expression, o
<span class="hljs-built_in">exports</span>.JSXEmptyExpression = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXEmptyExpression</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
<span class="hljs-built_in">exports</span>.JSXText = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXText</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(stringLiteral)</span> -&gt;</span>
super()
@value = stringLiteral.unquotedValueForJSX
@locationData = stringLiteral.locationData
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> {
@value
extra:
raw: @value
}
<span class="hljs-built_in">exports</span>.JSXAttribute = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXAttribute</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})</span> -&gt;</span>
super()
@value =
<span class="hljs-keyword">if</span> value?
value = value.base
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">instanceof</span> StringLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> value.shouldGenerateTemplateLiteral()
value
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> JSXExpressionContainer value
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span>
@value?.comments = value.comments
children: [<span class="hljs-string">&#x27;name&#x27;</span>, <span class="hljs-string">&#x27;value&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
compiledName = @name.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">return</span> compiledName <span class="hljs-keyword">unless</span> @value?
val = @value.compileToFragments o, LEVEL_LIST
compiledName.concat @makeCode(<span class="hljs-string">&#x27;=&#x27;</span>), val
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
name = @name
<span class="hljs-keyword">if</span> <span class="hljs-string">&#x27;:&#x27;</span> <span class="hljs-keyword">in</span> name.value
name = <span class="hljs-keyword">new</span> JSXNamespacedName name
<span class="hljs-keyword">return</span>
name: name.ast o
value: @value?.ast(o) ? <span class="hljs-literal">null</span>
<span class="hljs-built_in">exports</span>.JSXAttributes = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXAttributes</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(arr)</span> -&gt;</span>
super()
@attributes = []
<span class="hljs-keyword">for</span> object <span class="hljs-keyword">in</span> arr.objects
@checkValidAttribute object
{base} = object
<span class="hljs-keyword">if</span> base <span class="hljs-keyword">instanceof</span> IdentifierLiteral</pre></div></div>
</li>
<li id="section-131">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-131">&#x00a7;</a>
</div>
<p>attribute with no value eg disabled</p>
</div>
<div class="content"><div class='highlight'><pre> attribute = <span class="hljs-keyword">new</span> JSXAttribute name: <span class="hljs-keyword">new</span> JSXIdentifier(base.value).withLocationDataAndCommentsFrom base
attribute.locationData = base.locationData
@attributes.push attribute
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> base.generated</pre></div></div>
</li>
<li id="section-132">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-132">&#x00a7;</a>
</div>
<p>object spread attribute eg {…props}</p>
</div>
<div class="content"><div class='highlight'><pre> attribute = base.properties[<span class="hljs-number">0</span>]
attribute.jsx = <span class="hljs-literal">yes</span>
attribute.locationData = base.locationData
@attributes.push attribute
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-133">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-133">&#x00a7;</a>
</div>
<p>Obj containing attributes with values eg a=”b” c={d}</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> property <span class="hljs-keyword">in</span> base.properties
{variable, value} = property
attribute = <span class="hljs-keyword">new</span> JSXAttribute {
name: <span class="hljs-keyword">new</span> JSXIdentifier(variable.base.value).withLocationDataAndCommentsFrom variable.base
value
}
attribute.locationData = property.locationData
@attributes.push attribute
@locationData = arr.locationData
children: [<span class="hljs-string">&#x27;attributes&#x27;</span>]</pre></div></div>
</li>
<li id="section-134">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-134">&#x00a7;</a>
</div>
<p>Catch invalid attributes: &lt;div {a:”b”, props} {props} “value” /&gt;</p>
</div>
<div class="content"><div class='highlight'><pre> checkValidAttribute: <span class="hljs-function"><span class="hljs-params">(object)</span> -&gt;</span>
{base: attribute} = object
properties = attribute?.properties <span class="hljs-keyword">or</span> []
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (attribute <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">or</span> attribute <span class="hljs-keyword">instanceof</span> IdentifierLiteral) <span class="hljs-keyword">or</span> (attribute <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> attribute.generated <span class="hljs-keyword">and</span> (properties.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> (properties[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Splat)))
object.error <span class="hljs-string">&quot;&quot;&quot;
Unexpected token. Allowed JSX attributes are: id=&quot;val&quot;, src={source}, {props...} or attribute.
&quot;&quot;&quot;</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragments = []
<span class="hljs-keyword">for</span> attribute <span class="hljs-keyword">in</span> @attributes
fragments.push @makeCode <span class="hljs-string">&#x27; &#x27;</span>
fragments.push attribute.compileToFragments(o, LEVEL_TOP)...
fragments
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
attribute.ast(o) <span class="hljs-keyword">for</span> attribute <span class="hljs-keyword">in</span> @attributes
<span class="hljs-built_in">exports</span>.JSXNamespacedName = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXNamespacedName</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(tag)</span> -&gt;</span>
super()
[namespace, name] = tag.value.split <span class="hljs-string">&#x27;:&#x27;</span>
@namespace = <span class="hljs-keyword">new</span> JSXIdentifier(namespace).withLocationDataFrom locationData: extractSameLineLocationDataFirst(namespace.length) tag.locationData
@name = <span class="hljs-keyword">new</span> JSXIdentifier(name ).withLocationDataFrom locationData: extractSameLineLocationDataLast(name.length ) tag.locationData
@locationData = tag.locationData
children: [<span class="hljs-string">&#x27;namespace&#x27;</span>, <span class="hljs-string">&#x27;name&#x27;</span>]
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
namespace: @namespace.ast o
name: @name.ast o</pre></div></div>
</li>
<li id="section-135">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-135">&#x00a7;</a>
</div>
<p>Node for a JSX element</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.JSXElement = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JSXElement</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({@tagName, @attributes, @content})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;tagName&#x27;</span>, <span class="hljs-string">&#x27;attributes&#x27;</span>, <span class="hljs-string">&#x27;content&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@content?.base.jsx = <span class="hljs-literal">yes</span>
fragments = [@makeCode(<span class="hljs-string">&#x27;&lt;&#x27;</span>)]
fragments.push (tag = @tagName.compileToFragments(o, LEVEL_ACCESS))...
fragments.push @attributes.compileToFragments(o)...
<span class="hljs-keyword">if</span> @content
fragments.push @makeCode(<span class="hljs-string">&#x27;&gt;&#x27;</span>)
fragments.push @content.compileNode(o, LEVEL_LIST)...
fragments.push [@makeCode(<span class="hljs-string">&#x27;&lt;/&#x27;</span>), tag..., @makeCode(<span class="hljs-string">&#x27;&gt;&#x27;</span>)]...
<span class="hljs-keyword">else</span>
fragments.push @makeCode(<span class="hljs-string">&#x27; /&gt;&#x27;</span>)
fragments
isFragment: <span class="hljs-function">-&gt;</span>
!@tagName.base.value.length
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-136">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-136">&#x00a7;</a>
</div>
<p>The location data spanning the opening element &lt;&gt; is captured by
the generated Arr which contains the elements attributes</p>
</div>
<div class="content"><div class='highlight'><pre> @openingElementLocationData = jisonLocationDataToAstLocationData @attributes.locationData
tagName = @tagName.base
tagName.locationData = tagName.tagNameLocationData
<span class="hljs-keyword">if</span> @content?
@closingElementLocationData = mergeAstLocationData(
jisonLocationDataToAstLocationData tagName.closingTagOpeningBracketLocationData
jisonLocationDataToAstLocationData tagName.closingTagClosingBracketLocationData
)
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isFragment()
<span class="hljs-string">&#x27;JSXFragment&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;JSXElement&#x27;</span>
elementAstProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">tagNameAst</span> = =&gt;</span>
tag = @tagName.unwrap()
<span class="hljs-keyword">if</span> tag?.value <span class="hljs-keyword">and</span> <span class="hljs-string">&#x27;:&#x27;</span> <span class="hljs-keyword">in</span> tag.value
tag = <span class="hljs-keyword">new</span> JSXNamespacedName tag
tag.ast o
openingElement = <span class="hljs-built_in">Object</span>.assign {
type: <span class="hljs-string">&#x27;JSXOpeningElement&#x27;</span>
name: tagNameAst()
selfClosing: <span class="hljs-keyword">not</span> @closingElementLocationData?
attributes: @attributes.ast o
}, @openingElementLocationData
closingElement = <span class="hljs-literal">null</span>
<span class="hljs-keyword">if</span> @closingElementLocationData?
closingElement = <span class="hljs-built_in">Object</span>.assign {
type: <span class="hljs-string">&#x27;JSXClosingElement&#x27;</span>
name: <span class="hljs-built_in">Object</span>.assign(
tagNameAst(),
jisonLocationDataToAstLocationData @tagName.base.closingTagNameLocationData
)
}, @closingElementLocationData
<span class="hljs-keyword">if</span> closingElement.name.type <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;JSXMemberExpression&#x27;</span>, <span class="hljs-string">&#x27;JSXNamespacedName&#x27;</span>]
rangeDiff = closingElement.range[<span class="hljs-number">0</span>] - openingElement.range[<span class="hljs-number">0</span>] + <span class="hljs-string">&#x27;/&#x27;</span>.length
columnDiff = closingElement.loc.start.column - openingElement.loc.start.column + <span class="hljs-string">&#x27;/&#x27;</span>.length
<span class="hljs-function"> <span class="hljs-title">shiftAstLocationData</span> = <span class="hljs-params">(node)</span> =&gt;</span>
node.range = [
node.range[<span class="hljs-number">0</span>] + rangeDiff
node.range[<span class="hljs-number">1</span>] + rangeDiff
]
node.start += rangeDiff
node.end += rangeDiff
node.loc.start =
line: @closingElementLocationData.loc.start.line
column: node.loc.start.column + columnDiff
node.loc.end =
line: @closingElementLocationData.loc.start.line
column: node.loc.end.column + columnDiff
<span class="hljs-keyword">if</span> closingElement.name.type <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;JSXMemberExpression&#x27;</span>
currentExpr = closingElement.name
<span class="hljs-keyword">while</span> currentExpr.type <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;JSXMemberExpression&#x27;</span>
shiftAstLocationData currentExpr <span class="hljs-keyword">unless</span> currentExpr <span class="hljs-keyword">is</span> closingElement.name
shiftAstLocationData currentExpr.property
currentExpr = currentExpr.object
shiftAstLocationData currentExpr
<span class="hljs-keyword">else</span> <span class="hljs-comment"># JSXNamespacedName</span>
shiftAstLocationData closingElement.name.namespace
shiftAstLocationData closingElement.name.name
{openingElement, closingElement}
fragmentAstProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
openingFragment = <span class="hljs-built_in">Object</span>.assign {
type: <span class="hljs-string">&#x27;JSXOpeningFragment&#x27;</span>
}, @openingElementLocationData
closingFragment = <span class="hljs-built_in">Object</span>.assign {
type: <span class="hljs-string">&#x27;JSXClosingFragment&#x27;</span>
}, @closingElementLocationData
{openingFragment, closingFragment}
contentAst: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> [] <span class="hljs-keyword">unless</span> @content <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @content.base.isEmpty?()
content = @content.unwrapAll()
children =
<span class="hljs-keyword">if</span> content <span class="hljs-keyword">instanceof</span> StringLiteral
[<span class="hljs-keyword">new</span> JSXText content]
<span class="hljs-keyword">else</span> <span class="hljs-comment"># StringWithInterpolations</span>
<span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> @content.unwrapAll().extractElements o, includeInterpolationWrappers: <span class="hljs-literal">yes</span>, isJsx: <span class="hljs-literal">yes</span>
<span class="hljs-keyword">if</span> element <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">new</span> JSXText element
<span class="hljs-keyword">else</span> <span class="hljs-comment"># Interpolation</span>
{expression} = element
<span class="hljs-keyword">unless</span> expression?
emptyExpression = <span class="hljs-keyword">new</span> JSXEmptyExpression()
emptyExpression.locationData = emptyExpressionLocationData {
interpolationNode: element
openingBrace: <span class="hljs-string">&#x27;{&#x27;</span>
closingBrace: <span class="hljs-string">&#x27;}&#x27;</span>
}
<span class="hljs-keyword">new</span> JSXExpressionContainer emptyExpression, locationData: element.locationData
<span class="hljs-keyword">else</span>
unwrapped = expression.unwrapAll()
<span class="hljs-keyword">if</span> unwrapped <span class="hljs-keyword">instanceof</span> JSXElement <span class="hljs-keyword">and</span></pre></div></div>
</li>
<li id="section-137">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-137">&#x00a7;</a>
</div>
<p>distinguish <code>&lt;a&gt;&lt;b /&gt;&lt;/a&gt;</code> from <code>&lt;a&gt;{&lt;b /&gt;}&lt;/a&gt;</code></p>
</div>
<div class="content"><div class='highlight'><pre> unwrapped.locationData.range[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> element.locationData.range[<span class="hljs-number">0</span>]
unwrapped
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> JSXExpressionContainer unwrapped, locationData: element.locationData
child.ast(o) <span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> children <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> (child <span class="hljs-keyword">instanceof</span> JSXText <span class="hljs-keyword">and</span> child.value.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>)
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-built_in">Object</span>.assign(
<span class="hljs-keyword">if</span> @isFragment()
@fragmentAstProperties o
<span class="hljs-keyword">else</span>
@elementAstProperties o
,
children: @contentAst o
)
astLocationData: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @closingElementLocationData?
mergeAstLocationData @openingElementLocationData, @closingElementLocationData
<span class="hljs-keyword">else</span>
@openingElementLocationData</pre></div></div>
</li>
<li id="section-138">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-138">&#x00a7;</a>
</div>
<h3 id="call">Call</h3>
</div>
</li>
<li id="section-139">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-139">&#x00a7;</a>
</div>
<p>Node for a function invocation.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Call = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Call</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @args = [], @soak, @token)</span> -&gt;</span>
super()
@implicit = @args.implicit
@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">&quot;literal is not a function&quot;</span>
<span class="hljs-keyword">if</span> @variable.base <span class="hljs-keyword">instanceof</span> JSXTag
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> JSXElement(
tagName: @variable
attributes: <span class="hljs-keyword">new</span> JSXAttributes @args[<span class="hljs-number">0</span>].base
content: @args[<span class="hljs-number">1</span>]
)</pre></div></div>
</li>
<li id="section-140">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-140">&#x00a7;</a>
</div>
<p><code>@variable</code> never gets output as a result of this node getting created as
part of <code>RegexWithInterpolations</code>, so for that case move any comments to
the <code>args</code> property that gets passed into <code>RegexWithInterpolations</code> via
the grammar.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @variable.base?.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;RegExp&#x27;</span> <span class="hljs-keyword">and</span> @args.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
moveComments @variable, @args[<span class="hljs-number">0</span>]
children: [<span class="hljs-string">&#x27;variable&#x27;</span>, <span class="hljs-string">&#x27;args&#x27;</span>]</pre></div></div>
</li>
<li id="section-141">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-141">&#x00a7;</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 = <span class="hljs-built_in">Object</span>.assign {},
@locationData,
first_line: locationData.first_line
first_column: locationData.first_column
range: [
locationData.range[<span class="hljs-number">0</span>]
@locationData.range[<span class="hljs-number">1</span>]
]
base = @variable?.base <span class="hljs-keyword">or</span> @variable
<span class="hljs-keyword">if</span> base.needsUpdatedStartLocation
@variable.locationData = <span class="hljs-built_in">Object</span>.assign {},
@variable.locationData,
first_line: locationData.first_line
first_column: locationData.first_column
range: [
locationData.range[<span class="hljs-number">0</span>]
@variable.locationData.range[<span class="hljs-number">1</span>]
]
base.updateLocationDataIfMissing locationData
<span class="hljs-keyword">delete</span> @needsUpdatedStartLocation
super locationData</pre></div></div>
</li>
<li id="section-142">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-142">&#x00a7;</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>
this</pre></div></div>
</li>
<li id="section-143">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-143">&#x00a7;</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">&quot;Unsupported reference to &#x27;super&#x27;&quot;</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, this, <span class="hljs-string">&#x27;variable&#x27;</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">&quot;typeof <span class="hljs-subst">#{ left.compile o }</span> === \&quot;function\&quot;&quot;</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 = this
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">&#x27;variable&#x27;</span>
ifn</pre></div></div>
</li>
<li id="section-144">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-144">&#x00a7;</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>
@checkForNewSuper()
@variable?.front = @front
compiledArgs = []</pre></div></div>
</li>
<li id="section-145">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-145">&#x00a7;</a>
</div>
<p>If variable is <code>Accessor</code> fragments are cached and used later
in <code>Value::compileNode</code> to ensure correct order of the compilation,
and reuse of variables in the scope.
Example:
<code>a(x = 5).b(-&gt; x = 6)</code> should compile in the same order as
<code>a(x = 5); b(-&gt; x = 6)</code>
(see issue #4437, <a href="https://github.com/jashkenas/coffeescript/issues/4437">https://github.com/jashkenas/coffeescript/issues/4437</a>)</p>
</div>
<div class="content"><div class='highlight'><pre> varAccess = @variable?.properties?[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Access
argCode = (arg <span class="hljs-keyword">for</span> arg <span class="hljs-keyword">in</span> (@args || []) <span class="hljs-keyword">when</span> arg <span class="hljs-keyword">instanceof</span> Code)
<span class="hljs-keyword">if</span> argCode.length &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> varAccess <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @variable.base.cached
[cache] = @variable.base.cache o, LEVEL_ACCESS, <span class="hljs-function">-&gt;</span> <span class="hljs-literal">no</span>
@variable.base.cached = cache
<span class="hljs-keyword">for</span> arg, argIndex <span class="hljs-keyword">in</span> @args
<span class="hljs-keyword">if</span> argIndex <span class="hljs-keyword">then</span> compiledArgs.push @makeCode <span class="hljs-string">&quot;, &quot;</span>
compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
fragments = []
<span class="hljs-keyword">if</span> @isNew
fragments.push @makeCode <span class="hljs-string">&#x27;new &#x27;</span>
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @makeCode(<span class="hljs-string">&#x27;(&#x27;</span>), compiledArgs..., @makeCode(<span class="hljs-string">&#x27;)&#x27;</span>)
fragments
checkForNewSuper: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isNew
@variable.error <span class="hljs-string">&quot;Unsupported reference to &#x27;super&#x27;&quot;</span> <span class="hljs-keyword">if</span> @variable <span class="hljs-keyword">instanceof</span> Super
containsSoak: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @soak
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @variable?.containsSoak?()
<span class="hljs-literal">no</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @soak <span class="hljs-keyword">and</span> @variable <span class="hljs-keyword">instanceof</span> Super <span class="hljs-keyword">and</span> o.scope.namedMethod()?.ctor
@variable.error <span class="hljs-string">&quot;Unsupported reference to &#x27;super&#x27;&quot;</span>
@checkForNewSuper()
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isNew
<span class="hljs-string">&#x27;NewExpression&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @containsSoak()
<span class="hljs-string">&#x27;OptionalCallExpression&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;CallExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
callee: @variable.ast o, LEVEL_ACCESS
arguments: arg.ast(o, LEVEL_LIST) <span class="hljs-keyword">for</span> arg <span class="hljs-keyword">in</span> @args
optional: !!@soak
implicit: !!@implicit</pre></div></div>
</li>
<li id="section-146">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-146">&#x00a7;</a>
</div>
<h3 id="super">Super</h3>
</div>
</li>
<li id="section-147">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-147">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">&#x27;expressions&#x27;</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> super o <span class="hljs-keyword">unless</span> @expressions?.length
superCall = <span class="hljs-keyword">new</span> Literal fragmentsToText super 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-148">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-148">&#x00a7;</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
<span class="hljs-built_in">exports</span>.Super = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Super</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@accessor, @superLiteral)</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;accessor&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkInInstanceMethod o
method = o.scope.namedMethod()
<span class="hljs-keyword">unless</span> method.ctor? <span class="hljs-keyword">or</span> @accessor?
{name, variable} = method
<span class="hljs-keyword">if</span> name.shouldCache() <span class="hljs-keyword">or</span> (name <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">and</span> name.index.isAssignable())
nref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.parent.freeVariable <span class="hljs-string">&#x27;name&#x27;</span>
name.index = <span class="hljs-keyword">new</span> Assign nref, name.index
@accessor = <span class="hljs-keyword">if</span> nref? <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index nref <span class="hljs-keyword">else</span> name
<span class="hljs-keyword">if</span> @accessor?.name?.comments</pre></div></div>
</li>
<li id="section-149">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-149">&#x00a7;</a>
</div>
<p>A <code>super()</code> call gets compiled to e.g. <code>super.method()</code>, which means
the <code>method</code> property name gets compiled for the first time here, and
again when the <code>method:</code> property of the class gets compiled. Since
this compilation happens first, comments attached to <code>method:</code> would
get incorrectly output near <code>super.method()</code>, when we want them to
get output on the second pass when <code>method:</code> is output. So set them
aside during this compilation pass, and put them back on the object so
that theyre there for the later compilation.</p>
</div>
<div class="content"><div class='highlight'><pre> salvagedComments = @accessor.name.comments
<span class="hljs-keyword">delete</span> @accessor.name.comments
fragments = (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal <span class="hljs-string">&#x27;super&#x27;</span>), <span class="hljs-keyword">if</span> @accessor <span class="hljs-keyword">then</span> [ @accessor ] <span class="hljs-keyword">else</span> [])
.compileToFragments o
attachCommentsToNode salvagedComments, @accessor.name <span class="hljs-keyword">if</span> salvagedComments
fragments
checkInInstanceMethod: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
method = o.scope.namedMethod()
@error <span class="hljs-string">&#x27;cannot use super outside of an instance method&#x27;</span> <span class="hljs-keyword">unless</span> method?.isMethod
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkInInstanceMethod o
<span class="hljs-keyword">if</span> @accessor?
<span class="hljs-keyword">return</span> (
<span class="hljs-keyword">new</span> Value(
<span class="hljs-keyword">new</span> Super().withLocationDataFrom (@superLiteral ? @)
[@accessor]
).withLocationDataFrom @
).ast o
super o</pre></div></div>
</li>
<li id="section-150">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-150">&#x00a7;</a>
</div>
<h3 id="regexwithinterpolations">RegexWithInterpolations</h3>
</div>
</li>
<li id="section-151">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-151">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@call, {@heregexCommentTokens = []} = {})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;call&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@call.compileNode o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;InterpolatedRegExpLiteral&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
interpolatedPattern: @call.args[<span class="hljs-number">0</span>].ast o
flags: @call.args[<span class="hljs-number">1</span>]?.unwrap().originalValue ? <span class="hljs-string">&#x27;&#x27;</span>
comments:
<span class="hljs-keyword">for</span> heregexCommentToken <span class="hljs-keyword">in</span> @heregexCommentTokens
<span class="hljs-keyword">if</span> heregexCommentToken.here
<span class="hljs-keyword">new</span> HereComment(heregexCommentToken).ast o
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> LineComment(heregexCommentToken).ast o</pre></div></div>
</li>
<li id="section-152">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-152">&#x00a7;</a>
</div>
<h3 id="taggedtemplatecall">TaggedTemplateCall</h3>
</div>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.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 = StringWithInterpolations.fromStringLiteral arg <span class="hljs-keyword">if</span> arg <span class="hljs-keyword">instanceof</span> StringLiteral
super 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)
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;TaggedTemplateExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
tag: @variable.ast o, LEVEL_ACCESS
quasi: @args[<span class="hljs-number">0</span>].ast o, LEVEL_LIST</pre></div></div>
</li>
<li id="section-153">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-153">&#x00a7;</a>
</div>
<h3 id="extends">Extends</h3>
</div>
</li>
<li id="section-154">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-154">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;child&#x27;</span>, <span class="hljs-string">&#x27;parent&#x27;</span>]</pre></div></div>
</li>
<li id="section-155">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-155">&#x00a7;</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">&#x27;extend&#x27;</span>, o), [@child, @parent]).compileToFragments o</pre></div></div>
</li>
<li id="section-156">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-156">&#x00a7;</a>
</div>
<h3 id="access">Access</h3>
</div>
</li>
<li id="section-157">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-157">&#x00a7;</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><span class="hljs-built_in">exports</span>.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, {@soak, @shorthand} = {})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;name&#x27;</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
name = @name.compileToFragments o
node = @name.unwrap()
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> PropertyName
[@makeCode(<span class="hljs-string">&#x27;.&#x27;</span>), name...]
<span class="hljs-keyword">else</span>
[@makeCode(<span class="hljs-string">&#x27;[&#x27;</span>), name..., @makeCode(<span class="hljs-string">&#x27;]&#x27;</span>)]
shouldCache: NO
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-158">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-158">&#x00a7;</a>
</div>
<p>Babel doesnt have an AST node for <code>Access</code>, but rather just includes
this Access nodes child <code>name</code> Identifier node as the <code>property</code> of
the <code>MemberExpression</code> node.</p>
</div>
<div class="content"><div class='highlight'><pre> @name.ast o</pre></div></div>
</li>
<li id="section-159">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-159">&#x00a7;</a>
</div>
<h3 id="index">Index</h3>
</div>
</li>
<li id="section-160">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-160">&#x00a7;</a>
</div>
<p>A <code>[ ... ]</code> indexed access into an array or object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;index&#x27;</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[].concat @makeCode(<span class="hljs-string">&quot;[&quot;</span>), @index.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">&quot;]&quot;</span>)
shouldCache: <span class="hljs-function">-&gt;</span>
@index.shouldCache()
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-161">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-161">&#x00a7;</a>
</div>
<p>Babel doesnt have an AST node for <code>Index</code>, but rather just includes
this Index nodes child <code>index</code> Identifier node as the <code>property</code> of
the <code>MemberExpression</code> node. The fact that the <code>MemberExpression</code>s
<code>property</code> is an Index means that <code>computed</code> is <code>true</code> for the
<code>MemberExpression</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> @index.ast o</pre></div></div>
</li>
<li id="section-162">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-162">&#x00a7;</a>
</div>
<h3 id="range">Range</h3>
</div>
</li>
<li id="section-163">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-163">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">&#x27;from&#x27;</span>, <span class="hljs-string">&#x27;to&#x27;</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@from, @to, tag)</span> -&gt;</span>
super()
@exclusive = tag <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;exclusive&#x27;</span>
@equals = <span class="hljs-keyword">if</span> @exclusive <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;=&#x27;</span></pre></div></div>
</li>
<li id="section-164">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-164">&#x00a7;</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">&#x27;shouldCache&#x27;</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">&#x27;step&#x27;</span>
@fromNum = <span class="hljs-keyword">if</span> @from.isNumber() <span class="hljs-keyword">then</span> parseNumber @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> parseNumber @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> parseNumber @stepVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-165">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-165">&#x00a7;</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-166">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-166">&#x00a7;</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">&#x27;index&#x27;</span>
idxName = del o, <span class="hljs-string">&#x27;name&#x27;</span>
namedIndex = idxName <span class="hljs-keyword">and</span> idxName <span class="hljs-keyword">isnt</span> idx
varPart =
<span class="hljs-keyword">if</span> known <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> namedIndex
<span class="hljs-string">&quot;var <span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>&quot;</span>
varPart += <span class="hljs-string">&quot;, <span class="hljs-subst">#{@toC}</span>&quot;</span> <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar
varPart += <span class="hljs-string">&quot;, <span class="hljs-subst">#{@step}</span>&quot;</span> <span class="hljs-keyword">if</span> @step <span class="hljs-keyword">isnt</span> @stepVar
[lt, gt] = [<span class="hljs-string">&quot;<span class="hljs-subst">#{idx}</span> &lt;<span class="hljs-subst">#{@equals}</span>&quot;</span>, <span class="hljs-string">&quot;<span class="hljs-subst">#{idx}</span> &gt;<span class="hljs-subst">#{@equals}</span>&quot;</span>]</pre></div></div>
</li>
<li id="section-167">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-167">&#x00a7;</a>
</div>
<p>Generate the condition.</p>
</div>
<div class="content"><div class='highlight'><pre> [<span class="hljs-keyword">from</span>, to] = [@fromNum, @toNum]</pre></div></div>
</li>
<li id="section-168">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-168">&#x00a7;</a>
</div>
<p>Always check if the <code>step</code> isnt zero to avoid the infinite loop.</p>
</div>
<div class="content"><div class='highlight'><pre> stepNotZero = <span class="hljs-string">&quot;<span class="hljs-subst">#{ @stepNum ? @stepVar }</span> !== 0&quot;</span>
stepCond = <span class="hljs-string">&quot;<span class="hljs-subst">#{ @stepNum ? @stepVar }</span> &gt; 0&quot;</span>
lowerBound = <span class="hljs-string">&quot;<span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{ <span class="hljs-keyword">if</span> known <span class="hljs-keyword">then</span> to <span class="hljs-keyword">else</span> @toVar }</span>&quot;</span>
upperBound = <span class="hljs-string">&quot;<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{ <span class="hljs-keyword">if</span> known <span class="hljs-keyword">then</span> to <span class="hljs-keyword">else</span> @toVar }</span>&quot;</span>
condPart =
<span class="hljs-keyword">if</span> @step?
<span class="hljs-keyword">if</span> @stepNum? <span class="hljs-keyword">and</span> @stepNum <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> @stepNum &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{lowerBound}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{upperBound}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{stepNotZero}</span> &amp;&amp; (<span class="hljs-subst">#{stepCond}</span> ? <span class="hljs-subst">#{lowerBound}</span> : <span class="hljs-subst">#{upperBound}</span>)&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> known
<span class="hljs-string">&quot;<span class="hljs-subst">#{ <span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span> &lt;= to <span class="hljs-keyword">then</span> lt <span class="hljs-keyword">else</span> gt }</span> <span class="hljs-subst">#{to}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;(<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span> ? <span class="hljs-subst">#{lowerBound}</span> : <span class="hljs-subst">#{upperBound}</span>)&quot;</span>
cond = <span class="hljs-keyword">if</span> @stepVar <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{@stepVar}</span> &gt; 0&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>&quot;</span></pre></div></div>
</li>
<li id="section-169">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-169">&#x00a7;</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">&quot;<span class="hljs-subst">#{idx}</span> += <span class="hljs-subst">#{@stepVar}</span>&quot;</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">&quot;++<span class="hljs-subst">#{idx}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;--<span class="hljs-subst">#{idx}</span>&quot;</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">&quot;<span class="hljs-subst">#{idx}</span>++&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{idx}</span>--&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> namedIndex
<span class="hljs-string">&quot;<span class="hljs-subst">#{cond}</span> ? ++<span class="hljs-subst">#{idx}</span> : --<span class="hljs-subst">#{idx}</span>&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{idx}</span>++ : <span class="hljs-subst">#{idx}</span>--&quot;</span>
varPart = <span class="hljs-string">&quot;<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{varPart}</span>&quot;</span> <span class="hljs-keyword">if</span> namedIndex
stepPart = <span class="hljs-string">&quot;<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{stepPart}</span>&quot;</span> <span class="hljs-keyword">if</span> namedIndex</pre></div></div>
</li>
<li id="section-170">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-170">&#x00a7;</a>
</div>
<p>The final loop body.</p>
</div>
<div class="content"><div class='highlight'><pre> [@makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{varPart}</span>; <span class="hljs-subst">#{condPart}</span>; <span class="hljs-subst">#{stepPart}</span>&quot;</span>]</pre></div></div>
</li>
<li id="section-171">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-171">&#x00a7;</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> <span class="hljs-built_in">Math</span>.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">&quot;[<span class="hljs-subst">#{ range.join(<span class="hljs-string">&#x27;, &#x27;</span>) }</span>]&quot;</span>]
idt = @tab + TAB
i = o.scope.freeVariable <span class="hljs-string">&#x27;i&#x27;</span>, single: <span class="hljs-literal">true</span>, reserve: <span class="hljs-literal">no</span>
result = o.scope.freeVariable <span class="hljs-string">&#x27;results&#x27;</span>, reserve: <span class="hljs-literal">no</span>
pre = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{idt}</span>var <span class="hljs-subst">#{result}</span> = [];&quot;</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">&quot;<span class="hljs-subst">#{i}</span> = <span class="hljs-subst">#{@fromC}</span>&quot;</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">&quot;, <span class="hljs-subst">#{@toC}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>
cond = <span class="hljs-string">&quot;<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>&quot;</span>
body = <span class="hljs-string">&quot;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>--&quot;</span>
post = <span class="hljs-string">&quot;{ <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>&quot;</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">&#x27;, arguments&#x27;</span> <span class="hljs-keyword">if</span> hasArgs(@from) <span class="hljs-keyword">or</span> hasArgs(@to)
[@makeCode <span class="hljs-string">&quot;(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">&#x27;&#x27;</span>}</span>)&quot;</span>]
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> {
from: @from?.ast(o) ? <span class="hljs-literal">null</span>
to: @to?.ast(o) ? <span class="hljs-literal">null</span>
@exclusive
}</pre></div></div>
</li>
<li id="section-172">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-172">&#x00a7;</a>
</div>
<h3 id="slice">Slice</h3>
</div>
</li>
<li id="section-173">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-173">&#x00a7;</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><span class="hljs-built_in">exports</span>.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">&#x27;range&#x27;</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@range)</span> -&gt;</span>
super()</pre></div></div>
</li>
<li id="section-174">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-174">&#x00a7;</a>
</div>
<p>We have to be careful when trying to slice through the end of the array,
<code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>.
<code>9e9</code> should be safe because <code>9e9</code> &gt; <code>2**32</code>, the max array length.</p>
</div>
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{to, <span class="hljs-keyword">from</span>} = @range</pre></div></div>
</li>
<li id="section-175">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-175">&#x00a7;</a>
</div>
<p>Handle an expression in the property access, e.g. <code>a[!b in c..]</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span>?.shouldCache()
<span class="hljs-keyword">from</span> = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">from</span>
<span class="hljs-keyword">if</span> to?.shouldCache()
to = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens to
fromCompiled = <span class="hljs-keyword">from</span>?.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">or</span> [@makeCode <span class="hljs-string">&#x27;0&#x27;</span>]
<span class="hljs-keyword">if</span> to
compiled = to.compileToFragments o, LEVEL_PAREN
compiledText = fragmentsToText compiled
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">not</span> @range.exclusive <span class="hljs-keyword">and</span> +compiledText <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span>)
toStr = <span class="hljs-string">&#x27;, &#x27;</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">&quot;<span class="hljs-subst">#{+compiledText + <span class="hljs-number">1</span>}</span>&quot;</span>
<span class="hljs-keyword">else</span>
compiled = to.compileToFragments o, LEVEL_ACCESS
<span class="hljs-string">&quot;+<span class="hljs-subst">#{fragmentsToText compiled}</span> + 1 || 9e9&quot;</span>
[@makeCode <span class="hljs-string">&quot;.slice(<span class="hljs-subst">#{ fragmentsToText fromCompiled }</span><span class="hljs-subst">#{ toStr <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;&#x27;</span> }</span>)&quot;</span>]
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@range.ast o</pre></div></div>
</li>
<li id="section-176">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-176">&#x00a7;</a>
</div>
<h3 id="obj">Obj</h3>
</div>
</li>
<li id="section-177">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-177">&#x00a7;</a>
</div>
<p>An object literal, nothing fancy.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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>)</span> -&gt;</span>
super()
@objects = @properties = props <span class="hljs-keyword">or</span> []
children: [<span class="hljs-string">&#x27;properties&#x27;</span>]
isAssignable: <span class="hljs-function"><span class="hljs-params">(opts)</span> -&gt;</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties</pre></div></div>
</li>
<li id="section-178">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-178">&#x00a7;</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">&#x27;object&#x27;</span> <span class="hljs-keyword">and</span>
prop.value?.base <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Arr
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> prop.isAssignable opts
<span class="hljs-literal">yes</span>
shouldCache: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @isAssignable()</pre></div></div>
</li>
<li id="section-179">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-179">&#x00a7;</a>
</div>
<p>Check if object contains splat.</p>
</div>
<div class="content"><div class='highlight'><pre> hasSplat: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop <span class="hljs-keyword">instanceof</span> Splat
<span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-180">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-180">&#x00a7;</a>
</div>
<p>Move rest property to the end of the list.
<code>{a, rest..., b} = obj</code> -&gt; <code>{a, b, rest...} = obj</code>
<code>foo = ({a, rest..., b}) -&gt;</code> -&gt; <code>foo = {a, b, rest...}) -&gt;</code></p>
</div>
<div class="content"><div class='highlight'><pre> reorderProperties: <span class="hljs-function">-&gt;</span>
props = @properties
splatProps = @getAndCheckSplatProps()
splatProp = props.splice splatProps[<span class="hljs-number">0</span>], <span class="hljs-number">1</span>
@objects = @properties = [].concat props, splatProp
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@reorderProperties() <span class="hljs-keyword">if</span> @hasSplat() <span class="hljs-keyword">and</span> @lhs
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">&#x27;cannot have an implicit value in an implicit object&#x27;</span>
idt = o.indent += TAB
lastNode = @lastNode @properties</pre></div></div>
</li>
<li id="section-181">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-181">&#x00a7;</a>
</div>
<p>If this object is the left-hand side of an assignment, all its children
are too.</p>
</div>
<div class="content"><div class='highlight'><pre> @propagateLhs()
isCompact = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> @properties
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span>
isCompact = <span class="hljs-literal">no</span>
answer = []
answer.push @makeCode <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;\n&#x27;</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">&#x27;&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> isCompact
<span class="hljs-string">&#x27;, &#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">is</span> lastNode
<span class="hljs-string">&#x27;\n&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;,\n&#x27;</span>
indent = <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</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">&#x27;object&#x27;</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">&quot;unexpected <span class="hljs-subst">#{prop.operatorToken.value}</span>&quot;</span> <span class="hljs-keyword">unless</span> @lhs
prop.variable
<span class="hljs-keyword">else</span>
prop
<span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> key.hasProperties()
key.error <span class="hljs-string">&#x27;invalid object key&#x27;</span> <span class="hljs-keyword">if</span> prop.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> key.this
key = key.properties[<span class="hljs-number">0</span>].name
prop = <span class="hljs-keyword">new</span> Assign key, prop, <span class="hljs-string">&#x27;object&#x27;</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">&#x27;object&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> key.base <span class="hljs-keyword">instanceof</span> ComputedPropertyName</pre></div></div>
</li>
<li id="section-182">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-182">&#x00a7;</a>
</div>
<p><code>{ [foo()] }</code> output as <code>{ [ref = foo()]: ref }</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> prop.base.value.shouldCache()
[key, value] = prop.base.value.cache o
key = <span class="hljs-keyword">new</span> ComputedPropertyName key.value <span class="hljs-keyword">if</span> key <span class="hljs-keyword">instanceof</span> IdentifierLiteral
prop = <span class="hljs-keyword">new</span> Assign key, value, <span class="hljs-string">&#x27;object&#x27;</span>
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-183">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-183">&#x00a7;</a>
</div>
<p><code>{ [expression] }</code> output as <code>{ [expression]: expression }</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> prop = <span class="hljs-keyword">new</span> Assign key, prop.base.value, <span class="hljs-string">&#x27;object&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> prop.bareLiteral?(IdentifierLiteral) <span class="hljs-keyword">and</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Splat
prop = <span class="hljs-keyword">new</span> Assign prop, prop, <span class="hljs-string">&#x27;object&#x27;</span>
<span class="hljs-keyword">if</span> indent <span class="hljs-keyword">then</span> answer.push @makeCode indent
answer.push prop.compileToFragments(o, LEVEL_TOP)...
<span class="hljs-keyword">if</span> join <span class="hljs-keyword">then</span> answer.push @makeCode join
answer.push @makeCode <span class="hljs-keyword">if</span> isCompact <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>&quot;</span>
answer = @wrapInBraces answer
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer
getAndCheckSplatProps: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @hasSplat() <span class="hljs-keyword">and</span> @lhs
props = @properties
splatProps = (i <span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> prop <span class="hljs-keyword">instanceof</span> Splat)
props[splatProps[<span class="hljs-number">1</span>]].error <span class="hljs-string">&quot;multiple spread elements are disallowed&quot;</span> <span class="hljs-keyword">if</span> splatProps?.length &gt; <span class="hljs-number">1</span>
splatProps
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">&#x27;object&#x27;</span>
prop = prop.unwrapAll()
prop.eachName iterator <span class="hljs-keyword">if</span> prop.eachName?</pre></div></div>
</li>
<li id="section-184">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-184">&#x00a7;</a>
</div>
<p>Convert “bare” properties to <code>ObjectProperty</code>s (or <code>Splat</code>s).</p>
</div>
<div class="content"><div class='highlight'><pre> expandProperty: <span class="hljs-function"><span class="hljs-params">(property)</span> -&gt;</span>
{variable, context, operatorToken} = property
key = <span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span>
variable
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Assign
operatorToken.error <span class="hljs-string">&quot;unexpected <span class="hljs-subst">#{operatorToken.value}</span>&quot;</span> <span class="hljs-keyword">unless</span> @lhs
variable
<span class="hljs-keyword">else</span>
property
<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">&#x27;invalid object key&#x27;</span> <span class="hljs-keyword">unless</span> context <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;object&#x27;</span> <span class="hljs-keyword">and</span> key.this
<span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Assign
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ObjectProperty fromAssign: property
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ObjectProperty key: property
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ObjectProperty(fromAssign: property) <span class="hljs-keyword">unless</span> key <span class="hljs-keyword">is</span> property
<span class="hljs-keyword">return</span> property <span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Splat
<span class="hljs-keyword">new</span> ObjectProperty key: property
expandProperties: <span class="hljs-function">-&gt;</span>
@expandProperty(property) <span class="hljs-keyword">for</span> property <span class="hljs-keyword">in</span> @properties
propagateLhs: <span class="hljs-function"><span class="hljs-params">(setLhs)</span> -&gt;</span>
@lhs = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> setLhs
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @lhs
<span class="hljs-keyword">for</span> property <span class="hljs-keyword">in</span> @properties
<span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> property.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span>
{value} = property
unwrappedValue = value.unwrapAll()
<span class="hljs-keyword">if</span> unwrappedValue <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> unwrappedValue <span class="hljs-keyword">instanceof</span> Obj
unwrappedValue.propagateLhs <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> unwrappedValue <span class="hljs-keyword">instanceof</span> Assign
unwrappedValue.nestedLhs = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Assign</pre></div></div>
</li>
<li id="section-185">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-185">&#x00a7;</a>
</div>
<p>Shorthand property with default, e.g. <code>{a = 1} = b</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> property.nestedLhs = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> property <span class="hljs-keyword">instanceof</span> Splat
property.propagateLhs <span class="hljs-literal">yes</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@getAndCheckSplatProps()
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @lhs
<span class="hljs-string">&#x27;ObjectPattern&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;ObjectExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
implicit: !!@generated
properties:
property.ast(o) <span class="hljs-keyword">for</span> property <span class="hljs-keyword">in</span> @expandProperties()
<span class="hljs-built_in">exports</span>.ObjectProperty = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ObjectProperty</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({key, fromAssign})</span> -&gt;</span>
super()
<span class="hljs-keyword">if</span> fromAssign
{variable: @key, value, context} = fromAssign
<span class="hljs-keyword">if</span> context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span></pre></div></div>
</li>
<li id="section-186">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-186">&#x00a7;</a>
</div>
<p>All non-shorthand properties (i.e. includes <code>:</code>).</p>
</div>
<div class="content"><div class='highlight'><pre> @value = value
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-187">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-187">&#x00a7;</a>
</div>
<p>Left-hand-side shorthand with default e.g. <code>{a = 1} = b</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> @value = fromAssign
@shorthand = <span class="hljs-literal">yes</span>
@locationData = fromAssign.locationData
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-188">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-188">&#x00a7;</a>
</div>
<p>Shorthand without default e.g. <code>{a}</code> or <code>{@a}</code> or <code>{[a]}</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> @key = key
@shorthand = <span class="hljs-literal">yes</span>
@locationData = key.locationData
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
isComputedPropertyName = (@key <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @key.base <span class="hljs-keyword">instanceof</span> ComputedPropertyName) <span class="hljs-keyword">or</span> @key.unwrap() <span class="hljs-keyword">instanceof</span> StringWithInterpolations
keyAst = @key.ast o, LEVEL_LIST
<span class="hljs-keyword">return</span>
key:
<span class="hljs-keyword">if</span> keyAst?.declaration
<span class="hljs-built_in">Object</span>.assign {}, keyAst, declaration: <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span>
keyAst
value: @value?.ast(o, LEVEL_LIST) ? keyAst
shorthand: !!@shorthand
computed: !!isComputedPropertyName
method: <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-189">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-189">&#x00a7;</a>
</div>
<h3 id="arr">Arr</h3>
</div>
</li>
<li id="section-190">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-190">&#x00a7;</a>
</div>
<p>An array literal.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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>
super()
@objects = objs <span class="hljs-keyword">or</span> []
@propagateLhs()
children: [<span class="hljs-string">&#x27;objects&#x27;</span>]
hasElision: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Elision
<span class="hljs-literal">no</span>
isAssignable: <span class="hljs-function"><span class="hljs-params">(opts)</span> -&gt;</span>
{allowExpansion, allowNontrailingSplat, allowEmptyArray = <span class="hljs-literal">no</span>} = opts ? {}
<span class="hljs-keyword">return</span> allowEmptyArray <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> <span class="hljs-keyword">not</span> allowNontrailingSplat <span class="hljs-keyword">and</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> (allowExpansion <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion) <span class="hljs-keyword">or</span> (obj.isAssignable(opts) <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">&#x27;[]&#x27;</span>] <span class="hljs-keyword">unless</span> @objects.length
o.indent += TAB
<span class="hljs-function"> <span class="hljs-title">fragmentIsElision</span> = <span class="hljs-params">([ fragment ])</span> -&gt;</span>
fragment.type <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;Elision&#x27;</span> <span class="hljs-keyword">and</span> fragment.code.trim() <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;,&#x27;</span></pre></div></div>
</li>
<li id="section-191">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-191">&#x00a7;</a>
</div>
<p>Detect if <code>Elision</code>s at the beginning of the array are processed (e.g. [, , , a]).</p>
</div>
<div class="content"><div class='highlight'><pre> passedElision = <span class="hljs-literal">no</span>
answer = []
<span class="hljs-keyword">for</span> obj, objIndex <span class="hljs-keyword">in</span> @objects
unwrappedObj = obj.unwrapAll()</pre></div></div>
</li>
<li id="section-192">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-192">&#x00a7;</a>
</div>
<p>Let <code>compileCommentFragments</code> know to intersperse block comments
into the fragments created when compiling this array.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> unwrappedObj.comments <span class="hljs-keyword">and</span>
unwrappedObj.comments.filter(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> <span class="hljs-keyword">not</span> comment.here).length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
unwrappedObj.includeCommentFragments = YES
compiledObjs = (obj.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects)
olen = compiledObjs.length</pre></div></div>
</li>
<li id="section-193">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-193">&#x00a7;</a>
</div>
<p>If <code>compiledObjs</code> includes newlines, we will output this as a multiline
array (i.e. with a newline and indentation after the <code>[</code>). If an element
contains line comments, that should also trigger multiline output since
by definition line comments will introduce newlines into our output.
The exception is if only the first element has line comments; in that
case, output as the compact form if we otherwise would have, so that the
first elements line comments get output before or after the array.</p>
</div>
<div class="content"><div class='highlight'><pre> includesLineCommentsOnNonFirstElement = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledObjs
<span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = fragment.code.trim()
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> index <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> includesLineCommentsOnNonFirstElement <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">and</span> hasLineComments fragment
includesLineCommentsOnNonFirstElement = <span class="hljs-literal">yes</span></pre></div></div>
</li>
<li id="section-194">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-194">&#x00a7;</a>
</div>
<p>Add , if all <code>Elisions</code> from the beginning of the array are processed (e.g. [, , , a]) and
element isnt <code>Elision</code> or last element is <code>Elision</code> (e.g. [a,,b,,])</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> index <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> passedElision <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> fragmentIsElision(fragments) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">is</span> olen - <span class="hljs-number">1</span>)
answer.push @makeCode <span class="hljs-string">&#x27;, &#x27;</span>
passedElision = passedElision <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> fragmentIsElision fragments
answer.push fragments...
<span class="hljs-keyword">if</span> includesLineCommentsOnNonFirstElement <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">in</span> fragmentsToText(answer)
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> answer
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = <span class="hljs-string">&quot;<span class="hljs-subst">#{multident(fragment.code, o.indent, <span class="hljs-literal">no</span>)}</span>\n<span class="hljs-subst">#{o.indent}</span>&quot;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragment.code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;, &#x27;</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> fragment?.isElision <span class="hljs-keyword">and</span> fragment.type <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;StringLiteral&#x27;</span>, <span class="hljs-string">&#x27;StringWithInterpolations&#x27;</span>]
fragment.code = <span class="hljs-string">&quot;,\n<span class="hljs-subst">#{o.indent}</span>&quot;</span>
answer.unshift @makeCode <span class="hljs-string">&quot;[\n<span class="hljs-subst">#{o.indent}</span>&quot;</span>
answer.push @makeCode <span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>]&quot;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> answer <span class="hljs-keyword">when</span> fragment.isHereComment
fragment.code = <span class="hljs-string">&quot;<span class="hljs-subst">#{fragment.code}</span> &quot;</span>
answer.unshift @makeCode <span class="hljs-string">&#x27;[&#x27;</span>
answer.push @makeCode <span class="hljs-string">&#x27;]&#x27;</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-195">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-195">&#x00a7;</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> propagateLhs: <span class="hljs-function"><span class="hljs-params">(setLhs)</span> -&gt;</span>
@lhs = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> setLhs
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @lhs
<span class="hljs-keyword">for</span> object <span class="hljs-keyword">in</span> @objects
object.lhs = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> object <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">or</span> object <span class="hljs-keyword">instanceof</span> Expansion
unwrappedObject = object.unwrapAll()
<span class="hljs-keyword">if</span> unwrappedObject <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> unwrappedObject <span class="hljs-keyword">instanceof</span> Obj
unwrappedObject.propagateLhs <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> unwrappedObject <span class="hljs-keyword">instanceof</span> Assign
unwrappedObject.nestedLhs = <span class="hljs-literal">yes</span>
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @lhs
<span class="hljs-string">&#x27;ArrayPattern&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;ArrayExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
elements:
object.ast(o, LEVEL_LIST) <span class="hljs-keyword">for</span> object <span class="hljs-keyword">in</span> @objects</pre></div></div>
</li>
<li id="section-196">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-196">&#x00a7;</a>
</div>
<h3 id="class">Class</h3>
</div>
</li>
<li id="section-197">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-197">&#x00a7;</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>
<span class="hljs-built_in">exports</span>.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">&#x27;variable&#x27;</span>, <span class="hljs-string">&#x27;parent&#x27;</span>, <span class="hljs-string">&#x27;body&#x27;</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @parent, @body)</span> -&gt;</span>
super()
<span class="hljs-keyword">unless</span> @body?
@body = <span class="hljs-keyword">new</span> Block
@hasGeneratedBody = <span class="hljs-literal">yes</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name = @determineName()
executableBody = @walkBody o</pre></div></div>
</li>
<li id="section-198">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-198">&#x00a7;</a>
</div>
<p>Special handling to allow <code>class expr.A extends A</code> declarations</p>
</div>
<div class="content"><div class='highlight'><pre> parentName = @parent.base.value <span class="hljs-keyword">if</span> @parent <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @parent.hasProperties()
@hasNameClash = @name? <span class="hljs-keyword">and</span> @name <span class="hljs-keyword">is</span> parentName
node = @
<span class="hljs-keyword">if</span> executableBody <span class="hljs-keyword">or</span> @hasNameClash
node = <span class="hljs-keyword">new</span> ExecutableClassBody node, executableBody
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @name? <span class="hljs-keyword">and</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP</pre></div></div>
</li>
<li id="section-199">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-199">&#x00a7;</a>
</div>
<p>Anonymous classes are only valid in expressions</p>
</div>
<div class="content"><div class='highlight'><pre> node = <span class="hljs-keyword">new</span> Parens node
<span class="hljs-keyword">if</span> @boundMethods.length <span class="hljs-keyword">and</span> @parent
@variable ?= <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">&#x27;_class&#x27;</span>
[@variable, @variableRef] = @variable.cache o <span class="hljs-keyword">unless</span> @variableRef?
<span class="hljs-keyword">if</span> @variable
node = <span class="hljs-keyword">new</span> Assign @variable, node, <span class="hljs-literal">null</span>, { @moduleDeclaration }
@compileNode = @compileClassDeclaration
<span class="hljs-keyword">try</span>
<span class="hljs-keyword">return</span> node.compileToFragments o
<span class="hljs-keyword">finally</span>
<span class="hljs-keyword">delete</span> @compileNode
compileClassDeclaration: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@ctor ?= @makeDefaultConstructor() <span class="hljs-keyword">if</span> @externalCtor <span class="hljs-keyword">or</span> @boundMethods.length
@ctor?.noReturn = <span class="hljs-literal">true</span>
@proxyBoundMethods() <span class="hljs-keyword">if</span> @boundMethods.length
o.indent += TAB
result = []
result.push @makeCode <span class="hljs-string">&quot;class &quot;</span>
result.push @makeCode @name <span class="hljs-keyword">if</span> @name
@compileCommentFragments o, @variable, result <span class="hljs-keyword">if</span> @variable?.comments?
result.push @makeCode <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-keyword">if</span> @name
result.push @makeCode(<span class="hljs-string">&#x27;extends &#x27;</span>), @parent.compileToFragments(o)..., @makeCode <span class="hljs-string">&#x27; &#x27;</span> <span class="hljs-keyword">if</span> @parent
result.push @makeCode <span class="hljs-string">&#x27;{&#x27;</span>
<span class="hljs-keyword">unless</span> @body.isEmpty()
@body.spaced = <span class="hljs-literal">true</span>
result.push @makeCode <span class="hljs-string">&#x27;\n&#x27;</span>
result.push @body.compileToFragments(o, LEVEL_TOP)...
result.push @makeCode <span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>&quot;</span>
result.push @makeCode <span class="hljs-string">&#x27;}&#x27;</span>
result</pre></div></div>
</li>
<li id="section-200">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-200">&#x00a7;</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">&quot;_<span class="hljs-subst">#{name}</span>&quot;</span> <span class="hljs-keyword">else</span> name
walkBody: <span class="hljs-function"><span class="hljs-params">(o)</span> -&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, o
pushSlice()
exprs.push initializerExpression
initializer.push initializerExpression
start = end + <span class="hljs-number">1</span>
end++
pushSlice()
expressions[i..i] = exprs
i += exprs.length
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> initializerExpression = @addInitializerExpression expression, o
initializer.push initializerExpression
expressions[i] = initializerExpression
i += <span class="hljs-number">1</span>
<span class="hljs-keyword">for</span> method <span class="hljs-keyword">in</span> initializer <span class="hljs-keyword">when</span> method <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">if</span> method.ctor
method.error <span class="hljs-string">&#x27;Cannot define more than one constructor in a class&#x27;</span> <span class="hljs-keyword">if</span> @ctor
@ctor = method
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method.isStatic <span class="hljs-keyword">and</span> method.bound
method.context = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method.bound
@boundMethods.push method
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> o.compiling
<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-201">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-201">&#x00a7;</a>
</div>
<p>Add an expression to the class initializer</p>
<p>This is the key method for determining whether an expression in a class
body should appear in the initializer or the executable body. If the given
<code>node</code> is valid in a class body the method will return a (new, modified,
or identical) node for inclusion in the class initializer, otherwise
nothing will be returned and the node will appear in the executable body.</p>
<p>At time of writing, only methods (instance and static) are valid in ES
class initializers. As new ES class features (such as class fields) reach
Stage 4, this method will need to be updated to support them. We
additionally allow <code>PassthroughLiteral</code>s (backticked expressions) in the
initializer as an escape hatch for ES features that are not implemented
(e.g. getters and setters defined via the <code>get</code> and <code>set</code> keywords as
opposed to the <code>Object.defineProperty</code> method).</p>
</div>
<div class="content"><div class='highlight'><pre> addInitializerExpression: <span class="hljs-function"><span class="hljs-params">(node, o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> node.unwrapAll() <span class="hljs-keyword">instanceof</span> PassthroughLiteral
node
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @validInitializerMethod node
@addInitializerMethod node
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> o.compiling <span class="hljs-keyword">and</span> @validClassProperty node
@addClassProperty node
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> o.compiling <span class="hljs-keyword">and</span> @validClassPrototypeProperty node
@addClassPrototypeProperty node
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-202">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-202">&#x00a7;</a>
</div>
<p>Checks if the given node is a valid ES class initializer method.</p>
</div>
<div class="content"><div class='highlight'><pre> validInitializerMethod: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> node.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</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-203">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-203">&#x00a7;</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, operatorToken } = 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
isConstructor =
<span class="hljs-keyword">if</span> methodName <span class="hljs-keyword">instanceof</span> StringLiteral
methodName.originalValue <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;constructor&#x27;</span>
<span class="hljs-keyword">else</span>
methodName.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;constructor&#x27;</span>
method.ctor = (<span class="hljs-keyword">if</span> @parent <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;derived&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;base&#x27;</span>) <span class="hljs-keyword">if</span> isConstructor
method.error <span class="hljs-string">&#x27;Cannot define a constructor as a bound (fat arrow) function&#x27;</span> <span class="hljs-keyword">if</span> method.bound <span class="hljs-keyword">and</span> method.ctor
method.operatorToken = operatorToken
method
validClassProperty: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node <span class="hljs-keyword">instanceof</span> Assign
<span class="hljs-keyword">return</span> node.variable.looksStatic @name
addClassProperty: <span class="hljs-function"><span class="hljs-params">(assign)</span> -&gt;</span>
{variable, value, operatorToken} = assign
{staticClassName} = variable.looksStatic @name
<span class="hljs-keyword">new</span> ClassProperty({
name: variable.properties[<span class="hljs-number">0</span>]
isStatic: <span class="hljs-literal">yes</span>
staticClassName
value
operatorToken
}).withLocationDataFrom assign
validClassPrototypeProperty: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node <span class="hljs-keyword">instanceof</span> Assign
node.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> node.variable.hasProperties()
addClassPrototypeProperty: <span class="hljs-function"><span class="hljs-params">(assign)</span> -&gt;</span>
{variable, value} = assign
<span class="hljs-keyword">new</span> ClassPrototypeProperty({
name: variable.base
value
}).withLocationDataFrom assign
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">&#x27;constructor&#x27;</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">&#x27;arguments&#x27;</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">&#x27;apply&#x27;</span> ]
applyArgs = [ <span class="hljs-keyword">new</span> ThisLiteral, <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">&#x27;arguments&#x27;</span> ]
ctor.body.push <span class="hljs-keyword">new</span> Call applyCtor, applyArgs
ctor.body.makeReturn()
ctor
proxyBoundMethods: <span class="hljs-function">-&gt;</span>
@ctor.thisAssignments = <span class="hljs-keyword">for</span> method <span class="hljs-keyword">in</span> @boundMethods
method.classVariable = @variableRef <span class="hljs-keyword">if</span> @parent
name = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> ThisLiteral, [ method.name ])
<span class="hljs-keyword">new</span> Assign name, <span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(name, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">&#x27;bind&#x27;</span>]), [<span class="hljs-keyword">new</span> ThisLiteral])
<span class="hljs-literal">null</span>
declareName: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> (name = @variable?.unwrap()) <span class="hljs-keyword">instanceof</span> IdentifierLiteral
alreadyDeclared = o.scope.find name.value
name.isDeclaration = <span class="hljs-keyword">not</span> alreadyDeclared
isStatementAst: <span class="hljs-function">-&gt;</span> <span class="hljs-literal">yes</span>
astNode: <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">&#x27;Class bodies cannot contain pure statements&#x27;</span>
<span class="hljs-keyword">if</span> argumentsNode = @body.contains isLiteralArguments
argumentsNode.error <span class="hljs-string">&quot;Class bodies shouldn&#x27;t reference arguments&quot;</span>
@declareName o
@name = @determineName()
@body.isClassBody = <span class="hljs-literal">yes</span>
@body.locationData = zeroWidthLocationDataFromEndLocation @locationData <span class="hljs-keyword">if</span> @hasGeneratedBody
@walkBody o
sniffDirectives @body.expressions
@ctor?.noReturn = <span class="hljs-literal">yes</span>
super o
astType: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP
<span class="hljs-string">&#x27;ClassDeclaration&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;ClassExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
id: @variable?.ast(o) ? <span class="hljs-literal">null</span>
superClass: @parent?.ast(o, LEVEL_PAREN) ? <span class="hljs-literal">null</span>
body: @body.ast o, LEVEL_TOP
<span class="hljs-built_in">exports</span>.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">&#x27;class&#x27;</span>, <span class="hljs-string">&#x27;body&#x27;</span> ]
defaultClassVariableName: <span class="hljs-string">&#x27;_Class&#x27;</span>
constructor: <span class="hljs-function"><span class="hljs-params">(@class, @body = <span class="hljs-keyword">new</span> Block)</span> -&gt;</span>
super()
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">&#x27;Class bodies cannot contain pure statements&#x27;</span>
<span class="hljs-keyword">if</span> argumentsNode = @body.contains isLiteralArguments
argumentsNode.error <span class="hljs-string">&quot;Class bodies shouldn&#x27;t reference arguments&quot;</span>
params = []
args = [<span class="hljs-keyword">new</span> ThisLiteral]
wrapper = <span class="hljs-keyword">new</span> Code params, @body
klass = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Call (<span class="hljs-keyword">new</span> Value wrapper, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">&#x27;call&#x27;</span>]), args
@body.spaced = <span class="hljs-literal">true</span>
o.classScope = wrapper.makeScope o.scope
@name = @class.name ? o.classScope.freeVariable @defaultClassVariableName
ident = <span class="hljs-keyword">new</span> IdentifierLiteral @name
directives = @walkBody()
@setContext()
<span class="hljs-keyword">if</span> @class.hasNameClash
parent = <span class="hljs-keyword">new</span> IdentifierLiteral o.classScope.freeVariable <span class="hljs-string">&#x27;superClass&#x27;</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">&#x27;ctor&#x27;</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-204">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-204">&#x00a7;</a>
</div>
<p>Traverse the classs children and:</p>
<ul>
<li>Hoist valid ES properties into <code>@properties</code></li>
<li>Hoist static assignments into <code>@properties</code></li>
<li>Convert invalid ES properties into class or prototype assignments</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> walkBody: <span class="hljs-function">-&gt;</span>
directives = []
index = <span class="hljs-number">0</span>
<span class="hljs-keyword">while</span> expr = @body.expressions[index]
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isString()
<span class="hljs-keyword">if</span> expr.hoisted
index++
<span class="hljs-keyword">else</span>
directives.push @body.expressions.splice(index, <span class="hljs-number">1</span>)...
@traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">or</span> child <span class="hljs-keyword">instanceof</span> HoistTarget
cont = <span class="hljs-literal">true</span>
<span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> Block
<span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> child.expressions
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> node.isObject(<span class="hljs-literal">true</span>)
cont = <span class="hljs-literal">false</span>
child.expressions[i] = @addProperties node.base.properties
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> node.variable.looksStatic @name
node.value.isStatic = <span class="hljs-literal">yes</span>
child.expressions = flatten child.expressions
cont
directives
setContext: <span class="hljs-function">-&gt;</span>
@body.traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> ThisLiteral
node.value = @name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound <span class="hljs-keyword">and</span> (node.isStatic <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.name)
node.context = @name</pre></div></div>
</li>
<li id="section-205">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-205">&#x00a7;</a>
</div>
<p>Make class/prototype assignments for invalid ES properties</p>
</div>
<div class="content"><div class='highlight'><pre> addProperties: <span class="hljs-function"><span class="hljs-params">(assigns)</span> -&gt;</span>
result = <span class="hljs-keyword">for</span> assign <span class="hljs-keyword">in</span> assigns
variable = assign.variable
base = variable?.base
value = assign.value
<span class="hljs-keyword">delete</span> assign.context
<span class="hljs-keyword">if</span> base.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;constructor&#x27;</span>
<span class="hljs-keyword">if</span> value <span class="hljs-keyword">instanceof</span> Code
base.error <span class="hljs-string">&#x27;constructors must be defined at the top level of a class body&#x27;</span></pre></div></div>
</li>
<li id="section-206">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-206">&#x00a7;</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.this
name =
<span class="hljs-keyword">if</span> base <span class="hljs-keyword">instanceof</span> ComputedPropertyName
<span class="hljs-keyword">new</span> Index base.value
<span class="hljs-keyword">else</span>
<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">&#x27;prototype&#x27;</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
<span class="hljs-built_in">exports</span>.ClassProperty = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClassProperty</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">({@name, @isStatic, @staticClassName, @value, @operatorToken})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;name&#x27;</span>, <span class="hljs-string">&#x27;value&#x27;</span>, <span class="hljs-string">&#x27;staticClassName&#x27;</span>]
isStatement: YES
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
key: @name.ast o, LEVEL_LIST
value: @value.ast o, LEVEL_LIST
static: !!@isStatic
computed: @name <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">or</span> @name <span class="hljs-keyword">instanceof</span> ComputedPropertyName
operator: @operatorToken?.value ? <span class="hljs-string">&#x27;=&#x27;</span>
staticClassName: @staticClassName?.ast(o) ? <span class="hljs-literal">null</span>
<span class="hljs-built_in">exports</span>.ClassPrototypeProperty = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClassPrototypeProperty</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})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;name&#x27;</span>, <span class="hljs-string">&#x27;value&#x27;</span>]
isStatement: YES
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
key: @name.ast o, LEVEL_LIST
value: @value.ast o, LEVEL_LIST
computed: @name <span class="hljs-keyword">instanceof</span> ComputedPropertyName <span class="hljs-keyword">or</span> @name <span class="hljs-keyword">instanceof</span> StringWithInterpolations</pre></div></div>
</li>
<li id="section-207">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-207">&#x00a7;</a>
</div>
<h3 id="import-and-export">Import and Export</h3>
</div>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.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, @assertions)</span> -&gt;</span>
super()
@checkSource()
children: [<span class="hljs-string">&#x27;clause&#x27;</span>, <span class="hljs-string">&#x27;source&#x27;</span>, <span class="hljs-string">&#x27;assertions&#x27;</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">&#x27;the name of the module to be imported from must be an uninterpolated string&#x27;</span>
checkScope: <span class="hljs-function"><span class="hljs-params">(o, moduleDeclarationType)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-208">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-208">&#x00a7;</a>
</div>
<p>TODO: would be appropriate to flag this error during AST generation (as
well as when compiling to JS). But <code>o.indent</code> isnt tracked during AST
generation, and there doesnt seem to be a current alternative way to track
whether were at the “program top-level”.</p>
</div>
<div class="content"><div class='highlight'><pre> <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">&quot;<span class="hljs-subst">#{moduleDeclarationType}</span> statements must be at top-level scope&quot;</span>
astAssertions: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @assertions?.properties?
@assertions.properties.map (assertion) =&gt;
{ start, end, loc, left, right } = assertion.ast(o)
{ type: <span class="hljs-string">&#x27;ImportAttribute&#x27;</span>, start, end, loc, key: left, value: right }
<span class="hljs-keyword">else</span>
[]
<span class="hljs-built_in">exports</span>.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">&#x27;import&#x27;</span>
o.importedSymbols = []
code = []
code.push @makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>import &quot;</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">&#x27; from &#x27;</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
<span class="hljs-keyword">if</span> @assertions?
code.push @makeCode <span class="hljs-string">&#x27; assert &#x27;</span>
code.push @assertions.compileToFragments(o)...
code.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
code
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.importedSymbols = []
super o
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
ret =
specifiers: @clause?.ast(o) ? []
source: @source.ast o
assertions: @astAssertions(o)
ret.importKind = <span class="hljs-string">&#x27;value&#x27;</span> <span class="hljs-keyword">if</span> @clause
ret
<span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;defaultBinding&#x27;</span>, <span class="hljs-string">&#x27;namedImports&#x27;</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">&#x27;, &#x27;</span> <span class="hljs-keyword">if</span> @namedImports?
<span class="hljs-keyword">if</span> @namedImports?
code.push @namedImports.compileNode(o)...
code
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-209">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-209">&#x00a7;</a>
</div>
<p>The AST for <code>ImportClause</code> is the non-nested list of import specifiers
that will be the <code>specifiers</code> property of an <code>ImportDeclaration</code> AST</p>
</div>
<div class="content"><div class='highlight'><pre> compact flatten [
@defaultBinding?.ast o
@namedImports?.ast o
]
<span class="hljs-built_in">exports</span>.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">&#x27;export&#x27;</span>
@checkForAnonymousClassExport()
code = []
code.push @makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>export &quot;</span>
code.push @makeCode <span class="hljs-string">&#x27;default &#x27;</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)
code.push @makeCode <span class="hljs-string">&#x27;var &#x27;</span>
@clause.moduleDeclaration = <span class="hljs-string">&#x27;export&#x27;</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
<span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">&quot; from <span class="hljs-subst">#{@source.value}</span>&quot;</span>
<span class="hljs-keyword">if</span> @assertions?
code.push @makeCode <span class="hljs-string">&#x27; assert &#x27;</span>
code.push @assertions.compileToFragments(o)...
code.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
code</pre></div></div>
</li>
<li id="section-210">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-210">&#x00a7;</a>
</div>
<p>Prevent exporting an anonymous class; all exported members must be named</p>
</div>
<div class="content"><div class='highlight'><pre> checkForAnonymousClassExport: <span class="hljs-function">-&gt;</span>
<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> Class <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @clause.variable
@clause.error <span class="hljs-string">&#x27;anonymous classes cannot be exported&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkForAnonymousClassExport()
super o
<span class="hljs-built_in">exports</span>.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>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
ret =
source: @source?.ast(o) ? <span class="hljs-literal">null</span>
assertions: @astAssertions(o)
exportKind: <span class="hljs-string">&#x27;value&#x27;</span>
clauseAst = @clause.ast o
<span class="hljs-keyword">if</span> @clause <span class="hljs-keyword">instanceof</span> ExportSpecifierList
ret.specifiers = clauseAst
ret.declaration = <span class="hljs-literal">null</span>
<span class="hljs-keyword">else</span>
ret.specifiers = []
ret.declaration = clauseAst
ret
<span class="hljs-built_in">exports</span>.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>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
declaration: @clause.ast o
assertions: @astAssertions(o)
<span class="hljs-built_in">exports</span>.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>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
source: @source.ast o
assertions: @astAssertions(o)
exportKind: <span class="hljs-string">&#x27;value&#x27;</span>
<span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;specifiers&#x27;</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">&quot;{\n<span class="hljs-subst">#{o.indent}</span>&quot;</span>
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledList
code.push @makeCode(<span class="hljs-string">&quot;,\n<span class="hljs-subst">#{o.indent}</span>&quot;</span>) <span class="hljs-keyword">if</span> index
code.push fragments...
code.push @makeCode <span class="hljs-string">&quot;\n}&quot;</span>
<span class="hljs-keyword">else</span>
code.push @makeCode <span class="hljs-string">&#x27;{}&#x27;</span>
code
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
specifier.ast(o) <span class="hljs-keyword">for</span> specifier <span class="hljs-keyword">in</span> @specifiers
<span class="hljs-built_in">exports</span>.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>
<span class="hljs-built_in">exports</span>.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>
<span class="hljs-built_in">exports</span>.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>
super()
<span class="hljs-keyword">if</span> @original.comments <span class="hljs-keyword">or</span> @alias?.comments
@comments = []
@comments.push @original.comments... <span class="hljs-keyword">if</span> @original.comments
@comments.push @alias.comments... <span class="hljs-keyword">if</span> @alias?.comments</pre></div></div>
</li>
<li id="section-211">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-211">&#x00a7;</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">&#x27;original&#x27;</span>, <span class="hljs-string">&#x27;alias&#x27;</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@addIdentifierToScope o
code = []
code.push @makeCode @original.value
code.push @makeCode <span class="hljs-string">&quot; as <span class="hljs-subst">#{@alias.value}</span>&quot;</span> <span class="hljs-keyword">if</span> @alias?
code
addIdentifierToScope: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.scope.find @identifier, @moduleDeclarationType
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@addIdentifierToScope o
super o
<span class="hljs-built_in">exports</span>.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>
super imported, local, <span class="hljs-string">&#x27;import&#x27;</span>
addIdentifierToScope: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-212">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-212">&#x00a7;</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">&quot;&#x27;<span class="hljs-subst">#{@identifier}</span>&#x27; has already been declared&quot;</span>
<span class="hljs-keyword">else</span>
o.importedSymbols.push @identifier
super o
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
originalAst = @original.ast o
<span class="hljs-keyword">return</span>
imported: originalAst
local: @alias?.ast(o) ? originalAst
importKind: <span class="hljs-literal">null</span>
<span class="hljs-built_in">exports</span>.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>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
local: @original.ast o
<span class="hljs-built_in">exports</span>.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>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
local: @alias.ast o
<span class="hljs-built_in">exports</span>.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>
super local, exported, <span class="hljs-string">&#x27;export&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
originalAst = @original.ast o
<span class="hljs-keyword">return</span>
local: originalAst
exported: @alias?.ast(o) ? originalAst
<span class="hljs-built_in">exports</span>.DynamicImport = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicImport</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
compileNode: <span class="hljs-function">-&gt;</span>
[@makeCode <span class="hljs-string">&#x27;import&#x27;</span>]
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;Import&#x27;</span>
<span class="hljs-built_in">exports</span>.DynamicImportCall = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicImportCall</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkArguments()
super o
checkArguments: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">unless</span> <span class="hljs-number">1</span> &lt;= @args.length &lt;= <span class="hljs-number">2</span>
@error <span class="hljs-string">&#x27;import() accepts either one or two arguments&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkArguments()
super o</pre></div></div>
</li>
<li id="section-213">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-213">&#x00a7;</a>
</div>
<h3 id="assign">Assign</h3>
</div>
</li>
<li id="section-214">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-214">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
{@param, @subpattern, @operatorToken, @moduleDeclaration, @originalContext = @context} = options
@propagateLhs()
children: [<span class="hljs-string">&#x27;variable&#x27;</span>, <span class="hljs-string">&#x27;value&#x27;</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">&quot;?&quot;</span> <span class="hljs-keyword">in</span> @context)
checkNameAssignability: <span class="hljs-function"><span class="hljs-params">(o, varBase)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.scope.type(varBase.value) <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;import&#x27;</span>
varBase.error <span class="hljs-string">&quot;&#x27;<span class="hljs-subst">#{varBase.value}</span>&#x27; is read-only&quot;</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">&#x27;object&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;value&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;variable&#x27;</span>].assigns name
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
unfoldSoak o, this, <span class="hljs-string">&#x27;variable&#x27;</span>
addScopeVariables: (o, {</pre></div></div>
</li>
<li id="section-215">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-215">&#x00a7;</a>
</div>
<p>During AST generation, we need to allow assignment to these constructs
that are considered “unassignable” during compile-to-JS, while still
flagging things like <code>[null] = b</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> allowAssignmentToExpansion = <span class="hljs-literal">no</span>,
allowAssignmentToNontrailingSplat = <span class="hljs-literal">no</span>,
allowAssignmentToEmptyArray = <span class="hljs-literal">no</span>,
allowAssignmentToComplexSplat = <span class="hljs-literal">no</span>
} = {}) -&gt;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> <span class="hljs-keyword">not</span> @context <span class="hljs-keyword">or</span> @context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;**=&#x27;</span>
varBase = @variable.unwrapAll()
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> varBase.isAssignable {
allowExpansion: allowAssignmentToExpansion
allowNontrailingSplat: allowAssignmentToNontrailingSplat
allowEmptyArray: allowAssignmentToEmptyArray
allowComplexSplat: allowAssignmentToComplexSplat
}
@variable.error <span class="hljs-string">&quot;&#x27;<span class="hljs-subst">#{@variable.compile o}</span>&#x27; can&#x27;t be assigned&quot;</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-216">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-216">&#x00a7;</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> @checkNameAssignability o, name
<span class="hljs-keyword">if</span> @moduleDeclaration
o.scope.add name.value, @moduleDeclaration
name.isDeclaration = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @param
o.scope.add name.value,
<span class="hljs-keyword">if</span> @param <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;alwaysDeclare&#x27;</span>
<span class="hljs-string">&#x27;var&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;param&#x27;</span>
<span class="hljs-keyword">else</span>
alreadyDeclared = o.scope.find name.value
name.isDeclaration ?= <span class="hljs-keyword">not</span> alreadyDeclared</pre></div></div>
</li>
<li id="section-217">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-217">&#x00a7;</a>
</div>
<p>If this assignment identifier has one or more herecomments
attached, output them as part of the declarations line (unless
other herecomments are already staged there) for compatibility
with Flow typing. Dont do this if this assignment is for a
class, e.g. <code>ClassName = class ClassName {</code>, as Flow requires
the comment to be between the class name and the <code>{</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> name.comments <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.comments[name.value] <span class="hljs-keyword">and</span>
@value <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">and</span>
name.comments.every(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.multiline)
commentsNode = <span class="hljs-keyword">new</span> IdentifierLiteral name.value
commentsNode.comments = name.comments
commentFragments = []
@compileCommentFragments o, commentsNode, commentFragments
o.scope.comments[name.value] = commentFragments</pre></div></div>
</li>
<li id="section-218">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-218">&#x00a7;</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-219">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-219">&#x00a7;</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()
<span class="hljs-keyword">unless</span> @variable.isAssignable()
<span class="hljs-keyword">if</span> @variable.isObject() <span class="hljs-keyword">and</span> @variable.base.hasSplat()
<span class="hljs-keyword">return</span> @compileObjectDestruct o
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> @compileDestructuring o
<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> @isConditional()
<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">&#x27;//=&#x27;</span>, <span class="hljs-string">&#x27;%%=&#x27;</span>]
@addScopeVariables o
<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">&#x27;prototype&#x27;</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">&#x27;object&#x27;</span>
<span class="hljs-keyword">if</span> @variable.shouldCache()
compiledName.unshift @makeCode <span class="hljs-string">&#x27;[&#x27;</span>
compiledName.push @makeCode <span class="hljs-string">&#x27;]&#x27;</span>
<span class="hljs-keyword">return</span> compiledName.concat @makeCode(<span class="hljs-string">&#x27;: &#x27;</span>), val
answer = compiledName.concat @makeCode(<span class="hljs-string">&quot; <span class="hljs-subst">#{ @context <span class="hljs-keyword">or</span> <span class="hljs-string">&#x27;=&#x27;</span> }</span> &quot;</span>), val</pre></div></div>
</li>
<li id="section-220">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-220">&#x00a7;</a>
</div>
<p>Per <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration</a>,
if were destructuring without declaring, the destructuring assignment must be wrapped in parentheses.
The assignment is wrapped in parentheses if o.level has lower precedence than LEVEL_LIST (3)
(i.e. LEVEL_COND (4), LEVEL_OP (5) or LEVEL_ACCESS (6)), or if were destructuring object, e.g. {a,b} = obj.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> o.level &gt; LEVEL_LIST <span class="hljs-keyword">or</span> isValue <span class="hljs-keyword">and</span> @variable.base <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @nestedLhs <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@param <span class="hljs-keyword">is</span> <span class="hljs-literal">yes</span>)
@wrapInParentheses answer
<span class="hljs-keyword">else</span>
answer</pre></div></div>
</li>
<li id="section-221">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-221">&#x00a7;</a>
</div>
<p>Object rest property is not assignable: <code>{{a}...}</code></p>
</div>
<div class="content"><div class='highlight'><pre> compileObjectDestruct: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@variable.base.reorderProperties()
{properties: props} = @variable.base
[..., splat] = props
splatProp = splat.name
assigns = []
refVal = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">&#x27;ref&#x27;</span>
props.splice <span class="hljs-number">-1</span>, <span class="hljs-number">1</span>, <span class="hljs-keyword">new</span> Splat refVal
assigns.push <span class="hljs-keyword">new</span> Assign(<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Obj props), @value).compileToFragments o, LEVEL_LIST
assigns.push <span class="hljs-keyword">new</span> Assign(<span class="hljs-keyword">new</span> Value(splatProp), refVal).compileToFragments o, LEVEL_LIST
@joinFragmentArrays assigns, <span class="hljs-string">&#x27;, &#x27;</span></pre></div></div>
</li>
<li id="section-222">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-222">&#x00a7;</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} = this
{objects} = @variable.base
olen = objects.length</pre></div></div>
</li>
<li id="section-223">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-223">&#x00a7;</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
@disallowLoneExpansion()
{splats, expans, splatsAndExpans} = @getAndCheckSplatsAndExpansions()
isSplat = splats?.length &gt; <span class="hljs-number">0</span>
isExpans = expans?.length &gt; <span class="hljs-number">0</span>
vvar = value.compileToFragments o, LEVEL_LIST
vvarText = fragmentsToText vvar
assigns = []
<span class="hljs-function"> <span class="hljs-title">pushAssign</span> = <span class="hljs-params">(variable, val)</span> =&gt;</span>
assigns.push <span class="hljs-keyword">new</span> Assign(variable, val, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">if</span> isSplat
splatVar = objects[splats[<span class="hljs-number">0</span>]].name.unwrap()
<span class="hljs-keyword">if</span> splatVar <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> splatVar <span class="hljs-keyword">instanceof</span> Obj
splatVarRef = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">&#x27;ref&#x27;</span>
objects[splats[<span class="hljs-number">0</span>]].name = splatVarRef
<span class="hljs-function"> <span class="hljs-title">splatVarAssign</span> = -&gt;</span> pushAssign <span class="hljs-keyword">new</span> Value(splatVar), splatVarRef</pre></div></div>
</li>
<li id="section-224">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-224">&#x00a7;</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">&#x27;ref&#x27;</span>
assigns.push [@makeCode(ref + <span class="hljs-string">&#x27; = &#x27;</span>), vvar...]
vvar = [@makeCode ref]
vvarText = ref
<span class="hljs-function">
<span class="hljs-title">slicer</span> = <span class="hljs-params">(type)</span> -&gt;</span> (vvar, start, end = <span class="hljs-literal">no</span>) -&gt;
vvar = <span class="hljs-keyword">new</span> IdentifierLiteral vvar <span class="hljs-keyword">unless</span> vvar <span class="hljs-keyword">instanceof</span> Value
args = [vvar, <span class="hljs-keyword">new</span> NumberLiteral(start)]
args.push <span class="hljs-keyword">new</span> NumberLiteral end <span class="hljs-keyword">if</span> end
slice = <span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> IdentifierLiteral utility type, o), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">&#x27;call&#x27;</span>]
<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Call slice, args</pre></div></div>
</li>
<li id="section-225">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-225">&#x00a7;</a>
</div>
<p>Helper which outputs <code>[].slice</code> code.</p>
</div>
<div class="content"><div class='highlight'><pre> compSlice = slicer <span class="hljs-string">&quot;slice&quot;</span></pre></div></div>
</li>
<li id="section-226">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-226">&#x00a7;</a>
</div>
<p>Helper which outputs <code>[].splice</code> code.</p>
</div>
<div class="content"><div class='highlight'><pre> compSplice = slicer <span class="hljs-string">&quot;splice&quot;</span></pre></div></div>
</li>
<li id="section-227">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-227">&#x00a7;</a>
</div>
<p>Check if <code>objects</code> array contains any instance of <code>Assign</code>, e.g. {a:1}.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">hasObjAssigns</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
(i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span>)</pre></div></div>
</li>
<li id="section-228">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-228">&#x00a7;</a>
</div>
<p>Check if <code>objects</code> array contains any unassignable object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">objIsUnassignable</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> objs <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> obj.isAssignable()
<span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-229">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-229">&#x00a7;</a>
</div>
<p><code>objects</code> are complex when there is object assign ({a:1}),
unassignable object, or just a single node.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">complexObjects</span> = <span class="hljs-params">(objs)</span> -&gt;</span>
hasObjAssigns(objs).length <span class="hljs-keyword">or</span> objIsUnassignable(objs) <span class="hljs-keyword">or</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-230">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-230">&#x00a7;</a>
</div>
<p>“Complex” <code>objects</code> are processed in a loop.
Examples: [a, b, {c, r…}, d], [a, …, {b, r…}, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">loopObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
<span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objs</pre></div></div>
</li>
<li id="section-231">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-231">&#x00a7;</a>
</div>
<p><code>Elision</code> can be skipped.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Elision</pre></div></div>
</li>
<li id="section-232">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-232">&#x00a7;</a>
</div>
<p>If <code>obj</code> is {a: 1}</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;object&#x27;</span>
{variable: {base: idx}, value: vvar} = obj
{variable: vvar} = vvar <span class="hljs-keyword">if</span> vvar <span class="hljs-keyword">instanceof</span> Assign
idx =
<span class="hljs-keyword">if</span> vvar.this
vvar.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName vvar.unwrap().value
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
vval = <span class="hljs-keyword">new</span> Value value, [<span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> acc <span class="hljs-keyword">then</span> Access <span class="hljs-keyword">else</span> Index) idx]
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-233">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-233">&#x00a7;</a>
</div>
<p><code>obj</code> is [a…], {a…} or a</p>
</div>
<div class="content"><div class='highlight'><pre> vvar = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Value obj.name
<span class="hljs-keyword">else</span> obj
vval = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">then</span> compSlice(vvarTxt, i)
<span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarTxt), [<span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> NumberLiteral i]
message = isUnassignable vvar.unwrap().value
vvar.error message <span class="hljs-keyword">if</span> message
pushAssign vvar, vval</pre></div></div>
</li>
<li id="section-234">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-234">&#x00a7;</a>
</div>
<p>“Simple” <code>objects</code> can be split and compiled to arrays, [a, b, c] = arr, [a, b, c…] = arr</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"> <span class="hljs-title">assignObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> =&gt;</span>
vvar = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Arr(objs, <span class="hljs-literal">yes</span>)
vval = <span class="hljs-keyword">if</span> vvarTxt <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">then</span> vvarTxt <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarTxt)
pushAssign vvar, vval
<span class="hljs-function">
<span class="hljs-title">processObjects</span> = <span class="hljs-params">(objs, vvar, vvarTxt)</span> -&gt;</span>
<span class="hljs-keyword">if</span> complexObjects objs
loopObjects objs, vvar, vvarTxt
<span class="hljs-keyword">else</span>
assignObjects objs, vvar, vvarTxt</pre></div></div>
</li>
<li id="section-235">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-235">&#x00a7;</a>
</div>
<p>In case there is <code>Splat</code> or <code>Expansion</code> in <code>objects</code>,
we can split array in two simple subarrays.
<code>Splat</code> [a, b, c…, d, e] can be split into [a, b, c…] and [d, e].
<code>Expansion</code> [a, b, …, c, d] can be split into [a, b] and [c, d].
Examples:
a) <code>Splat</code>
CS: [a, b, c…, d, e] = arr
JS: [a, b, …c] = arr, [d, e] = splice.call(c, -2)
b) <code>Expansion</code>
CS: [a, b, …, d, e] = arr
JS: [a, b] = arr, [d, e] = slice.call(arr, -2)</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> splatsAndExpans.length
expIdx = splatsAndExpans[<span class="hljs-number">0</span>]
leftObjs = objects.slice <span class="hljs-number">0</span>, expIdx + (<span class="hljs-keyword">if</span> isSplat <span class="hljs-keyword">then</span> <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-number">0</span>)
rightObjs = objects.slice expIdx + <span class="hljs-number">1</span>
processObjects leftObjs, vvar, vvarText <span class="hljs-keyword">if</span> leftObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> rightObjs.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span></pre></div></div>
</li>
<li id="section-236">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-236">&#x00a7;</a>
</div>
<p>Slice or splice <code>objects</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> refExp = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> isSplat <span class="hljs-keyword">then</span> compSplice <span class="hljs-keyword">new</span> Value(objects[expIdx].name), rightObjs.length * <span class="hljs-number">-1</span>
<span class="hljs-keyword">when</span> isExpans <span class="hljs-keyword">then</span> compSlice vvarText, rightObjs.length * <span class="hljs-number">-1</span>
<span class="hljs-keyword">if</span> complexObjects rightObjs
restVar = refExp
refExp = o.scope.freeVariable <span class="hljs-string">&#x27;ref&#x27;</span>
assigns.push [@makeCode(refExp + <span class="hljs-string">&#x27; = &#x27;</span>), restVar.compileToFragments(o, LEVEL_LIST)...]
processObjects rightObjs, vvar, refExp
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-237">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-237">&#x00a7;</a>
</div>
<p>There is no <code>Splat</code> or <code>Expansion</code> in <code>objects</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> processObjects objects, vvar, vvarText
splatVarAssign?()
assigns.push vvar <span class="hljs-keyword">unless</span> top <span class="hljs-keyword">or</span> @subpattern
fragments = @joinFragmentArrays assigns, <span class="hljs-string">&#x27;, &#x27;</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-238">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-238">&#x00a7;</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> disallowLoneExpansion: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @variable.base <span class="hljs-keyword">instanceof</span> Arr
{objects} = @variable.base
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> objects?.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
[loneObject] = objects
<span class="hljs-keyword">if</span> loneObject <span class="hljs-keyword">instanceof</span> Expansion
loneObject.error <span class="hljs-string">&#x27;Destructuring assignment has no target&#x27;</span></pre></div></div>
</li>
<li id="section-239">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-239">&#x00a7;</a>
</div>
<p>Show error if there is more than one <code>Splat</code>, or <code>Expansion</code>.
Examples: [a, b, c…, d, e, f…], [a, b, …, c, d, …], [a, b, …, c, d, e…]</p>
</div>
<div class="content"><div class='highlight'><pre> getAndCheckSplatsAndExpansions: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> {splats: [], expans: [], splatsAndExpans: []} <span class="hljs-keyword">unless</span> @variable.base <span class="hljs-keyword">instanceof</span> Arr
{objects} = @variable.base</pre></div></div>
</li>
<li id="section-240">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-240">&#x00a7;</a>
</div>
<p>Count all <code>Splats</code>: [a, b, c…, d, e]</p>
</div>
<div class="content"><div class='highlight'><pre> splats = (i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat)</pre></div></div>
</li>
<li id="section-241">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-241">&#x00a7;</a>
</div>
<p>Count all <code>Expansions</code>: [a, b, …, c, d]</p>
</div>
<div class="content"><div class='highlight'><pre> expans = (i <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Expansion)</pre></div></div>
</li>
<li id="section-242">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-242">&#x00a7;</a>
</div>
<p>Combine splats and expansions.</p>
</div>
<div class="content"><div class='highlight'><pre> splatsAndExpans = [splats..., expans...]
<span class="hljs-keyword">if</span> splatsAndExpans.length &gt; <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-243">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-243">&#x00a7;</a>
</div>
<p>Sort splatsAndExpans so we can show error at first disallowed token.</p>
</div>
<div class="content"><div class='highlight'><pre> objects[splatsAndExpans.sort()[<span class="hljs-number">1</span>]].error <span class="hljs-string">&quot;multiple splats/expansions are disallowed in an assignment&quot;</span>
{splats, expans, splatsAndExpans}</pre></div></div>
</li>
<li id="section-244">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-244">&#x00a7;</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-245">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-245">&#x00a7;</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
@throwUnassignableConditionalError left.base.value
<span class="hljs-keyword">if</span> <span class="hljs-string">&quot;?&quot;</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">&#x27;if&#x27;</span>).addElse(<span class="hljs-keyword">new</span> Assign(right, @value, <span class="hljs-string">&#x27;=&#x27;</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">&#x27;=&#x27;</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-246">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-246">&#x00a7;</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-247">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-247">&#x00a7;</a>
</div>
<p>Compile the assignment from an array splice literal, using JavaScripts
<code>Array#splice</code> method.</p>
</div>
<div class="content"><div class='highlight'><pre> compileSplice: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{range: {<span class="hljs-keyword">from</span>, to, exclusive}} = @variable.properties.pop()
unwrappedVar = @variable.unwrapAll()
<span class="hljs-keyword">if</span> unwrappedVar.comments
moveComments unwrappedVar, @
<span class="hljs-keyword">delete</span> @variable.comments
name = @variable.compile o
<span class="hljs-keyword">if</span> <span class="hljs-keyword">from</span>
[fromDecl, fromRef] = @cacheToCodeFragments <span class="hljs-keyword">from</span>.cache o, LEVEL_OP
<span class="hljs-keyword">else</span>
fromDecl = fromRef = <span class="hljs-string">&#x27;0&#x27;</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">&#x27; - &#x27;</span> + fromRef
to += <span class="hljs-string">&#x27; + 1&#x27;</span> <span class="hljs-keyword">unless</span> exclusive
<span class="hljs-keyword">else</span>
to = <span class="hljs-string">&quot;9e9&quot;</span>
[valDef, valRef] = @value.cache o, LEVEL_LIST
answer = [].concat @makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{utility <span class="hljs-string">&#x27;splice&#x27;</span>, o}</span>.apply(<span class="hljs-subst">#{name}</span>, [<span class="hljs-subst">#{fromDecl}</span>, <span class="hljs-subst">#{to}</span>].concat(&quot;</span>), valDef, @makeCode(<span class="hljs-string">&quot;)), &quot;</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
isDefaultAssignment: <span class="hljs-function">-&gt;</span> @param <span class="hljs-keyword">or</span> @nestedLhs
propagateLhs: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @variable?.isArray?() <span class="hljs-keyword">or</span> @variable?.isObject?()</pre></div></div>
</li>
<li id="section-248">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-248">&#x00a7;</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.propagateLhs <span class="hljs-literal">yes</span>
throwUnassignableConditionalError: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@variable.error <span class="hljs-string">&quot;the variable \&quot;<span class="hljs-subst">#{name}</span>\&quot; can&#x27;t be assigned with <span class="hljs-subst">#{@context}</span> because it has not been declared before&quot;</span>
isConditional: <span class="hljs-function">-&gt;</span>
@context <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;||=&#x27;</span>, <span class="hljs-string">&#x27;&amp;&amp;=&#x27;</span>, <span class="hljs-string">&#x27;?=&#x27;</span>]
isStatementAst: NO
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@disallowLoneExpansion()
@getAndCheckSplatsAndExpansions()
<span class="hljs-keyword">if</span> @isConditional()
variable = @variable.unwrap()
<span class="hljs-keyword">if</span> variable <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check variable.value
@throwUnassignableConditionalError variable.value
@addScopeVariables o, allowAssignmentToExpansion: <span class="hljs-literal">yes</span>, allowAssignmentToNontrailingSplat: <span class="hljs-literal">yes</span>, allowAssignmentToEmptyArray: <span class="hljs-literal">yes</span>, allowAssignmentToComplexSplat: <span class="hljs-literal">yes</span>
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isDefaultAssignment()
<span class="hljs-string">&#x27;AssignmentPattern&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;AssignmentExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
ret =
right: @value.ast o, LEVEL_LIST
left: @variable.ast o, LEVEL_LIST
<span class="hljs-keyword">unless</span> @isDefaultAssignment()
ret.operator = @originalContext ? <span class="hljs-string">&#x27;=&#x27;</span>
ret</pre></div></div>
</li>
<li id="section-249">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-249">&#x00a7;</a>
</div>
<h3 id="funcglyph">FuncGlyph</h3>
</div>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.FuncGlyph = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FuncGlyph</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@glyph)</span> -&gt;</span>
super()</pre></div></div>
</li>
<li id="section-250">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-250">&#x00a7;</a>
</div>
<h3 id="code">Code</h3>
</div>
</li>
<li id="section-251">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-251">&#x00a7;</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><span class="hljs-built_in">exports</span>.Code = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(params, body, @funcGlyph, @paramStart)</span> -&gt;</span>
super()
@params = params <span class="hljs-keyword">or</span> []
@body = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block
@bound = @funcGlyph?.glyph <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;=&gt;&#x27;</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> node <span class="hljs-keyword">instanceof</span> For <span class="hljs-keyword">and</span> node.isAwait()
@isAsync = <span class="hljs-literal">yes</span>
@propagateLhs()
children: [<span class="hljs-string">&#x27;params&#x27;</span>, <span class="hljs-string">&#x27;body&#x27;</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, this</pre></div></div>
</li>
<li id="section-252">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-252">&#x00a7;</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>
@checkForAsyncOrGeneratorConstructor()
<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">&#x27;this&#x27;</span> <span class="hljs-keyword">unless</span> @context
@updateOptions o
params = []
exprs = []
thisAssignments = @thisAssignments?.slice() ? []
paramsAfterSplat = []
haveSplatParam = <span class="hljs-literal">no</span>
haveBodyParam = <span class="hljs-literal">no</span>
@checkForDuplicateParams()
@disallowLoneExpansionAndMultipleSplats()</pre></div></div>
</li>
<li id="section-253">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-253">&#x00a7;</a>
</div>
<p>Separate <code>this</code> assignments.</p>
</div>
<div class="content"><div class='highlight'><pre> @eachParamName (name, node, param, obj) -&gt;
<span class="hljs-keyword">if</span> node.this
name = node.properties[<span class="hljs-number">0</span>].name.value
name = <span class="hljs-string">&quot;_<span class="hljs-subst">#{name}</span>&quot;</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN
target = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable name, reserve: <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-254">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-254">&#x00a7;</a>
</div>
<p><code>Param</code> is object destructuring with a default value: ({@prop = 1}) -&gt;
In a case when the variable name is already reserved, we have to assign
a new variable name to the destructured variable: ({prop:prop1 = 1}) -&gt;</p>
</div>
<div class="content"><div class='highlight'><pre> replacement =
<span class="hljs-keyword">if</span> param.name <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span>
obj.operatorToken.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;=&#x27;</span>
<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> IdentifierLiteral name), target, <span class="hljs-string">&#x27;object&#x27;</span> <span class="hljs-comment">#, operatorToken: new Literal &#x27;:&#x27;</span>
<span class="hljs-keyword">else</span>
target
param.renameParam node, replacement
thisAssignments.push <span class="hljs-keyword">new</span> Assign node, target</pre></div></div>
</li>
<li id="section-255">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-255">&#x00a7;</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-256">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-256">&#x00a7;</a>
</div>
<p>Was <code>...</code> used with this parameter? 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
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 <span class="hljs-keyword">or</span> param.name <span class="hljs-keyword">instanceof</span> Obj</pre></div></div>
</li>
<li id="section-257">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-257">&#x00a7;</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">&#x27;arg&#x27;</span>
params.push ref = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral splatParamName
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), ref
<span class="hljs-keyword">else</span>
params.push ref = param.asReference o
splatParamName = fragmentsToText ref.compileNodeWithoutComments o
<span class="hljs-keyword">if</span> param.shouldCache()
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), ref
<span class="hljs-keyword">else</span> <span class="hljs-comment"># `param` is an Expansion</span>
splatParamName = o.scope.freeVariable <span class="hljs-string">&#x27;args&#x27;</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-258">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-258">&#x00a7;</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-259">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-259">&#x00a7;</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">&#x27;===&#x27;</span>, param, <span class="hljs-keyword">new</span> UndefinedLiteral
ifTrue = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.value
exprs.push <span class="hljs-keyword">new</span> If condition, ifTrue
<span class="hljs-keyword">else</span>
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.asReference(o), <span class="hljs-literal">null</span>, param: <span class="hljs-string">&#x27;alwaysDeclare&#x27;</span></pre></div></div>
</li>
<li id="section-260">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-260">&#x00a7;</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-261">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-261">&#x00a7;</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-262">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-262">&#x00a7;</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-263">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-263">&#x00a7;</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>
<span class="hljs-keyword">unless</span> param.shouldCache()
param.name.eachName (prop) -&gt;
o.scope.parameter prop.value
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-264">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-264">&#x00a7;</a>
</div>
<p>This compilation of the parameter is only to get its name to add
to the scope name tracking; since the compilation output here
isnt kept for eventual output, dont include comments in this
compilation, so that they get output the “real” time this param
is compiled.</p>
</div>
<div class="content"><div class='highlight'><pre> paramToAddToScope = <span class="hljs-keyword">if</span> param.value? <span class="hljs-keyword">then</span> param <span class="hljs-keyword">else</span> ref
o.scope.parameter fragmentsToText paramToAddToScope.compileToFragmentsWithoutComments o
params.push ref
<span class="hljs-keyword">else</span>
paramsAfterSplat.push param</pre></div></div>
</li>
<li id="section-265">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-265">&#x00a7;</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">&#x27;===&#x27;</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-266">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-266">&#x00a7;</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">&#x27;var&#x27;</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> param.name?.value?</pre></div></div>
</li>
<li id="section-267">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-267">&#x00a7;</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-268">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-268">&#x00a7;</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-269">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-269">&#x00a7;</a>
</div>
<p>Add new expressions to the function body</p>
</div>
<div class="content"><div class='highlight'><pre> wasEmpty = @body.isEmpty()
@disallowSuperInParamDefaults()
@checkSuperCallsInConstructorBody()
@body.expressions.unshift thisAssignments... <span class="hljs-keyword">unless</span> @expandCtorSuper thisAssignments
@body.expressions.unshift exprs...
<span class="hljs-keyword">if</span> @isMethod <span class="hljs-keyword">and</span> @bound <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @isStatic <span class="hljs-keyword">and</span> @classVariable
boundMethodCheck = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">&#x27;boundMethodCheck&#x27;</span>, o
@body.expressions.unshift <span class="hljs-keyword">new</span> Call(boundMethodCheck, [<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> ThisLiteral), @classVariable])
@body.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> @noReturn</pre></div></div>
</li>
<li id="section-270">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-270">&#x00a7;</a>
</div>
<p>JavaScript doesnt allow bound (<code>=&gt;</code>) functions to also be generators.
This is usually caught via <code>Op::compileContinuation</code>, but double-check:</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @bound <span class="hljs-keyword">and</span> @isGenerator
yieldNode = @body.contains (node) -&gt; node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;yield&#x27;</span>
(yieldNode <span class="hljs-keyword">or</span> @).error <span class="hljs-string">&#x27;yield cannot occur inside bound (fat arrow) functions&#x27;</span></pre></div></div>
</li>
<li id="section-271">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-271">&#x00a7;</a>
</div>
<p>Assemble the output</p>
</div>
<div class="content"><div class='highlight'><pre> modifiers = []
modifiers.push <span class="hljs-string">&#x27;static&#x27;</span> <span class="hljs-keyword">if</span> @isMethod <span class="hljs-keyword">and</span> @isStatic
modifiers.push <span class="hljs-string">&#x27;async&#x27;</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">&quot;function<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isGenerator <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;*&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>&quot;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @isGenerator
modifiers.push <span class="hljs-string">&#x27;*&#x27;</span>
signature = [@makeCode <span class="hljs-string">&#x27;(&#x27;</span>]</pre></div></div>
</li>
<li id="section-272">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-272">&#x00a7;</a>
</div>
<p>Block comments between a function name and <code>(</code> get output between
<code>function</code> and <code>(</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @paramStart?.comments?
@compileCommentFragments o, @paramStart, signature
<span class="hljs-keyword">for</span> param, i <span class="hljs-keyword">in</span> params
signature.push @makeCode <span class="hljs-string">&#x27;, &#x27;</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
signature.push @makeCode <span class="hljs-string">&#x27;...&#x27;</span> <span class="hljs-keyword">if</span> haveSplatParam <span class="hljs-keyword">and</span> i <span class="hljs-keyword">is</span> params.length - <span class="hljs-number">1</span></pre></div></div>
</li>
<li id="section-273">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-273">&#x00a7;</a>
</div>
<p>Compile this parameter, but if any generated variables get created
(e.g. <code>ref</code>), shift those into the parent scope since we cant put a
<code>var</code> line inside a function parameter list.</p>
</div>
<div class="content"><div class='highlight'><pre> scopeVariablesCount = o.scope.variables.length
signature.push param.compileToFragments(o, LEVEL_PAREN)...
<span class="hljs-keyword">if</span> scopeVariablesCount <span class="hljs-keyword">isnt</span> o.scope.variables.length
generatedVariables = o.scope.variables.splice scopeVariablesCount
o.scope.parent.variables.push generatedVariables...
signature.push @makeCode <span class="hljs-string">&#x27;)&#x27;</span></pre></div></div>
</li>
<li id="section-274">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-274">&#x00a7;</a>
</div>
<p>Block comments between <code>)</code> and <code>-&gt;</code>/<code>=&gt;</code> get output between <code>)</code> and <code>{</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @funcGlyph?.comments?
comment.unshift = <span class="hljs-literal">no</span> <span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> @funcGlyph.comments
@compileCommentFragments o, @funcGlyph, signature
body = @body.compileWithDeclarations o <span class="hljs-keyword">unless</span> @body.isEmpty()</pre></div></div>
</li>
<li id="section-275">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-275">&#x00a7;</a>
</div>
<p>We need to compile the body before method names to ensure <code>super</code>
references are handled.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @isMethod
[methodScope, o.scope] = [o.scope, o.scope.parent]
name = @name.compileToFragments o
name.shift() <span class="hljs-keyword">if</span> name[<span class="hljs-number">0</span>].code <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;.&#x27;</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">&#x27; &#x27;</span>
answer.push @makeCode <span class="hljs-string">&#x27; &#x27;</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">&#x27; =&gt;&#x27;</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">&#x27; {&#x27;</span>
answer.push @makeCode(<span class="hljs-string">&#x27;\n&#x27;</span>), body..., @makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>&quot;</span>) <span class="hljs-keyword">if</span> body?.length
answer.push @makeCode <span class="hljs-string">&#x27;}&#x27;</span>
<span class="hljs-keyword">return</span> indentInitial answer, @ <span class="hljs-keyword">if</span> @isMethod
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">or</span> (o.level &gt;= LEVEL_ACCESS) <span class="hljs-keyword">then</span> @wrapInParentheses answer <span class="hljs-keyword">else</span> answer
updateOptions: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.scope = del(o, <span class="hljs-string">&#x27;classScope&#x27;</span>) <span class="hljs-keyword">or</span> @makeScope o.scope
o.scope.shared = del(o, <span class="hljs-string">&#x27;sharedScope&#x27;</span>)
o.indent += TAB
<span class="hljs-keyword">delete</span> o.bare
<span class="hljs-keyword">delete</span> o.isExistentialEquals
checkForDuplicateParams: <span class="hljs-function">-&gt;</span>
paramNames = []
@eachParamName (name, node, param) -&gt;
node.error <span class="hljs-string">&quot;multiple parameters named &#x27;<span class="hljs-subst">#{name}</span>&#x27;&quot;</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> paramNames
paramNames.push name
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-276">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-276">&#x00a7;</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>
super(crossScope, func) <span class="hljs-keyword">if</span> crossScope</pre></div></div>
</li>
<li id="section-277">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-277">&#x00a7;</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
super child, replacement
<span class="hljs-keyword">else</span>
<span class="hljs-literal">false</span>
disallowSuperInParamDefaults: <span class="hljs-function"><span class="hljs-params">({forAst} = {})</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">&quot;&#x27;super&#x27; is not allowed in constructor parameter defaults&quot;</span>
, checkForThisBeforeSuper: <span class="hljs-keyword">not</span> forAst
checkSuperCallsInConstructorBody: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">unless</span> @ctor
seenSuper = @eachSuperCall @body, <span class="hljs-function"><span class="hljs-params">(superCall)</span> =&gt;</span>
superCall.error <span class="hljs-string">&quot;&#x27;super&#x27; is only allowed in derived class constructors&quot;</span> <span class="hljs-keyword">if</span> @ctor <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;base&#x27;</span>
seenSuper
flagThisParamInDerivedClassConstructorWithoutCallingSuper: <span class="hljs-function"><span class="hljs-params">(param)</span> -&gt;</span>
param.error <span class="hljs-string">&quot;Can&#x27;t use @params in derived class constructors without calling super&quot;</span>
checkForAsyncOrGeneratorConstructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @ctor
@name.error <span class="hljs-string">&#x27;Class constructor may not be async&#x27;</span> <span class="hljs-keyword">if</span> @isAsync
@name.error <span class="hljs-string">&#x27;Class constructor may not be a generator&#x27;</span> <span class="hljs-keyword">if</span> @isGenerator
disallowLoneExpansionAndMultipleSplats: <span class="hljs-function">-&gt;</span>
seenSplatParam = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params</pre></div></div>
</li>
<li id="section-278">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-278">&#x00a7;</a>
</div>
<p>Was <code>...</code> used with this parameter? (Only one such parameter is allowed
per function.)</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> seenSplatParam
param.error <span class="hljs-string">&#x27;only one splat or expansion parameter is allowed per function definition&#x27;</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">&#x27;an expansion parameter cannot be the only parameter in a function definition&#x27;</span>
seenSplatParam = <span class="hljs-literal">yes</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
seenSuper = @eachSuperCall @body, <span class="hljs-function"><span class="hljs-params">(superCall)</span> =&gt;</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">&#x27;derived&#x27;</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
@flagThisParamInDerivedClassConstructorWithoutCallingSuper param
seenSuper</pre></div></div>
</li>
<li id="section-279">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-279">&#x00a7;</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, {checkForThisBeforeSuper = <span class="hljs-literal">yes</span>} = {})</span> -&gt;</span>
seenSuper = <span class="hljs-literal">no</span>
context.traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =&gt;</span>
<span class="hljs-keyword">if</span> child <span class="hljs-keyword">instanceof</span> SuperCall</pre></div></div>
</li>
<li id="section-280">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-280">&#x00a7;</a>
</div>
<p><code>super</code> in a constructor (the only <code>super</code> without an accessor)
cannot be given an argument with a reference to <code>this</code>, as that would
be referencing <code>this</code> before calling <code>super</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> child.variable.accessor
childArgs = child.args.filter (arg) -&gt;
arg <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Class <span class="hljs-keyword">and</span> (arg <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">or</span> arg.bound)
Block.wrap(childArgs).traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
node.error <span class="hljs-string">&quot;Can&#x27;t call super with @params in derived class constructors&quot;</span> <span class="hljs-keyword">if</span> node.this
seenSuper = <span class="hljs-literal">yes</span>
iterator child
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> checkForThisBeforeSuper <span class="hljs-keyword">and</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">&#x27;derived&#x27;</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> seenSuper
child.error <span class="hljs-string">&quot;Can&#x27;t reference &#x27;this&#x27; before calling super in derived class constructors&quot;</span></pre></div></div>
</li>
<li id="section-281">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-281">&#x00a7;</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
propagateLhs: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params
{name} = param
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Arr <span class="hljs-keyword">or</span> name <span class="hljs-keyword">instanceof</span> Obj
name.propagateLhs <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> param <span class="hljs-keyword">instanceof</span> Expansion
param.lhs = <span class="hljs-literal">yes</span>
astAddParamsToScope: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@eachParamName (name) -&gt;
o.scope.add name, <span class="hljs-string">&#x27;param&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@updateOptions o
@checkForAsyncOrGeneratorConstructor()
@checkForDuplicateParams()
@disallowSuperInParamDefaults forAst: <span class="hljs-literal">yes</span>
@disallowLoneExpansionAndMultipleSplats()
seenSuper = @checkSuperCallsInConstructorBody()
<span class="hljs-keyword">if</span> @ctor <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;derived&#x27;</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> seenSuper
@eachParamName (name, node) =&gt;
<span class="hljs-keyword">if</span> node.this
@flagThisParamInDerivedClassConstructorWithoutCallingSuper node
@astAddParamsToScope o
@body.makeReturn <span class="hljs-literal">null</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">unless</span> @body.isEmpty() <span class="hljs-keyword">or</span> @noReturn
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isMethod
<span class="hljs-string">&#x27;ClassMethod&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @bound
<span class="hljs-string">&#x27;ArrowFunctionExpression&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;FunctionExpression&#x27;</span>
paramForAst: <span class="hljs-function"><span class="hljs-params">(param)</span> -&gt;</span>
<span class="hljs-keyword">return</span> param <span class="hljs-keyword">if</span> param <span class="hljs-keyword">instanceof</span> Expansion
{name, value, splat} = param
<span class="hljs-keyword">if</span> splat
<span class="hljs-keyword">new</span> Splat name, lhs: <span class="hljs-literal">yes</span>, postfix: splat.postfix
.withLocationDataFrom param
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value?
<span class="hljs-keyword">new</span> Assign name, value, <span class="hljs-literal">null</span>, param: <span class="hljs-literal">yes</span>
.withLocationDataFrom locationData: mergeLocationData name.locationData, value.locationData
<span class="hljs-keyword">else</span>
name
methodAstProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">getIsComputed</span> = =&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @name <span class="hljs-keyword">instanceof</span> Index
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @name <span class="hljs-keyword">instanceof</span> ComputedPropertyName
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @name.name <span class="hljs-keyword">instanceof</span> ComputedPropertyName
<span class="hljs-literal">no</span>
<span class="hljs-keyword">return</span>
static: !!@isStatic
key: @name.ast o
computed: getIsComputed()
kind:
<span class="hljs-keyword">if</span> @ctor
<span class="hljs-string">&#x27;constructor&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;method&#x27;</span>
operator: @operatorToken?.value ? <span class="hljs-string">&#x27;=&#x27;</span>
staticClassName: @isStatic.staticClassName?.ast(o) ? <span class="hljs-literal">null</span>
bound: !!@bound
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.assign
params: @paramForAst(param).ast(o) <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params
body: @body.ast (<span class="hljs-built_in">Object</span>.assign {}, o, checkForDirectives: <span class="hljs-literal">yes</span>), LEVEL_TOP
generator: !!@isGenerator
async: !!@isAsync</pre></div></div>
</li>
<li id="section-282">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-282">&#x00a7;</a>
</div>
<p>We never generate named functions, so specify <code>id</code> as <code>null</code>, which
matches the Babel AST for anonymous function expressions/arrow functions</p>
</div>
<div class="content"><div class='highlight'><pre> id: <span class="hljs-literal">null</span>
hasIndentedBody: @body.locationData.first_line &gt; @funcGlyph?.locationData.first_line
,
<span class="hljs-keyword">if</span> @isMethod <span class="hljs-keyword">then</span> @methodAstProperties o <span class="hljs-keyword">else</span> {}
astLocationData: <span class="hljs-function">-&gt;</span>
functionLocationData = super()
<span class="hljs-keyword">return</span> functionLocationData <span class="hljs-keyword">unless</span> @isMethod
astLocationData = mergeAstLocationData @name.astLocationData(), functionLocationData
<span class="hljs-keyword">if</span> @isStatic.staticClassName?
astLocationData = mergeAstLocationData @isStatic.staticClassName.astLocationData(), astLocationData
astLocationData</pre></div></div>
</li>
<li id="section-283">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-283">&#x00a7;</a>
</div>
<h3 id="param">Param</h3>
</div>
</li>
<li id="section-284">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-284">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
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">&quot;unexpected <span class="hljs-subst">#{token.value}</span>&quot;</span>
children: [<span class="hljs-string">&#x27;name&#x27;</span>, <span class="hljs-string">&#x27;value&#x27;</span>]
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragments o, LEVEL_LIST
compileToFragmentsWithoutComments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragmentsWithoutComments o, LEVEL_LIST
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> @reference <span class="hljs-keyword">if</span> @reference
node = @name
<span class="hljs-keyword">if</span> node.this
name = node.properties[<span class="hljs-number">0</span>].name.value
name = <span class="hljs-string">&quot;_<span class="hljs-subst">#{name}</span>&quot;</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">&#x27;arg&#x27;</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-285">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-285">&#x00a7;</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">checkAssignabilityOfLiteral</span> = <span class="hljs-params">(literal)</span> -&gt;</span>
message = isUnassignable literal.value
<span class="hljs-keyword">if</span> message
literal.error message
<span class="hljs-keyword">unless</span> literal.isAssignable()
literal.error <span class="hljs-string">&quot;&#x27;<span class="hljs-subst">#{literal.value}</span>&#x27; can&#x27;t be assigned&quot;</span>
<span class="hljs-function">
<span class="hljs-title">atParam</span> = <span class="hljs-params">(obj, originalObj = <span class="hljs-literal">null</span>)</span> =&gt;</span> iterator <span class="hljs-string">&quot;@<span class="hljs-subst">#{obj.properties[<span class="hljs-number">0</span>].name.value}</span>&quot;</span>, obj, @, originalObj
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Call
name.error <span class="hljs-string">&quot;Function invocation can&#x27;t be assigned&quot;</span></pre></div></div>
</li>
<li id="section-286">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-286">&#x00a7;</a>
</div>
<ul>
<li>simple literals <code>foo</code></li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Literal
checkAssignabilityOfLiteral name
<span class="hljs-keyword">return</span> iterator name.value, name, @</pre></div></div>
</li>
<li id="section-287">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-287">&#x00a7;</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-288">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-288">&#x00a7;</a>
</div>
<p>Save original obj.</p>
</div>
<div class="content"><div class='highlight'><pre> nObj = obj</pre></div></div>
</li>
<li id="section-289">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-289">&#x00a7;</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-290">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-290">&#x00a7;</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-291">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-291">&#x00a7;</a>
</div>
<p>… possibly with a default value</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.value <span class="hljs-keyword">instanceof</span> Assign
obj = obj.value.variable
<span class="hljs-keyword">else</span>
obj = obj.value
@eachName iterator, obj.unwrap()</pre></div></div>
</li>
<li id="section-292">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-292">&#x00a7;</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-293">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-293">&#x00a7;</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-294">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-294">&#x00a7;</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.this
atParam obj, nObj</pre></div></div>
</li>
<li id="section-295">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-295">&#x00a7;</a>
</div>
<ul>
<li>simple destructured parameters {foo}</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span>
checkAssignabilityOfLiteral obj.base
iterator obj.base.value, obj.base, @
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Elision
obj
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">&quot;illegal parameter <span class="hljs-subst">#{obj.compile()}</span>&quot;</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
<li id="section-296">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-296">&#x00a7;</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.this</pre></div></div>
</li>
<li id="section-297">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-297">&#x00a7;</a>
</div>
<p>No need to assign a new variable for the destructured variable if the variable isnt reserved.
Examples:
<code>({@foo}) -&gt;</code> should compile to <code>({foo}) { this.foo = foo}</code>
<code>foo = 1; ({@foo}) -&gt;</code> should compile to <code>foo = 1; ({foo:foo1}) { this.foo = foo1 }</code></p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> node.this <span class="hljs-keyword">and</span> key.value <span class="hljs-keyword">is</span> newNode.value
<span class="hljs-keyword">new</span> Value newNode
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(key), newNode, <span class="hljs-string">&#x27;object&#x27;</span>
<span class="hljs-keyword">else</span>
newNode
@replaceInContext isNode, replacement</pre></div></div>
</li>
<li id="section-298">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-298">&#x00a7;</a>
</div>
<h3 id="splat">Splat</h3>
</div>
</li>
<li id="section-299">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-299">&#x00a7;</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><span class="hljs-built_in">exports</span>.Splat = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Splat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(name, {@lhs, @postfix = <span class="hljs-literal">true</span>} = {})</span> -&gt;</span>
super()
@name = <span class="hljs-keyword">if</span> name.compile <span class="hljs-keyword">then</span> name <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Literal name
children: [<span class="hljs-string">&#x27;name&#x27;</span>]
shouldCache: <span class="hljs-function">-&gt;</span> <span class="hljs-literal">no</span>
isAssignable: <span class="hljs-function"><span class="hljs-params">({allowComplexSplat = <span class="hljs-literal">no</span>} = {})</span>-&gt;</span>
<span class="hljs-keyword">return</span> allowComplexSplat <span class="hljs-keyword">if</span> @name <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">or</span> @name <span class="hljs-keyword">instanceof</span> Parens
@name.isAssignable() <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> @name.isAtomic <span class="hljs-keyword">or</span> @name.isAtomic())
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@name.assigns name
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
compiledSplat = [@makeCode(<span class="hljs-string">&#x27;...&#x27;</span>), @name.compileToFragments(o, LEVEL_OP)...]
<span class="hljs-keyword">return</span> compiledSplat <span class="hljs-keyword">unless</span> @jsx
<span class="hljs-keyword">return</span> [@makeCode(<span class="hljs-string">&#x27;{&#x27;</span>), compiledSplat..., @makeCode(<span class="hljs-string">&#x27;}&#x27;</span>)]
unwrap: <span class="hljs-function">-&gt;</span> @name
propagateLhs: <span class="hljs-function"><span class="hljs-params">(setLhs)</span> -&gt;</span>
@lhs = <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> setLhs
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> @lhs
@name.propagateLhs? <span class="hljs-literal">yes</span>
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @jsx
<span class="hljs-string">&#x27;JSXSpreadAttribute&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @lhs
<span class="hljs-string">&#x27;RestElement&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;SpreadElement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> {
argument: @name.ast o, LEVEL_OP
@postfix
}</pre></div></div>
</li>
<li id="section-300">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-300">&#x00a7;</a>
</div>
<h3 id="expansion">Expansion</h3>
</div>
</li>
<li id="section-301">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-301">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
@throwLhsError()
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
this
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
throwLhsError: <span class="hljs-function">-&gt;</span>
@error <span class="hljs-string">&#x27;Expansion must be used inside a destructuring assignment or parameter list&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> @lhs
@throwLhsError()
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;RestElement&#x27;</span>
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
argument: <span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-302">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-302">&#x00a7;</a>
</div>
<h3 id="elision">Elision</h3>
</div>
</li>
<li id="section-303">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-303">&#x00a7;</a>
</div>
<p>Array elision element (for example, [,a, , , b, , c, ,]).</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Elision = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Elision</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
isAssignable: YES
shouldCache: NO
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
fragment = super o, level
fragment.isElision = <span class="hljs-literal">yes</span>
fragment
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-string">&#x27;, &#x27;</span>]
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
this
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span>
astNode: <span class="hljs-function">-&gt;</span>
<span class="hljs-literal">null</span></pre></div></div>
</li>
<li id="section-304">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-304">&#x00a7;</a>
</div>
<h3 id="while">While</h3>
</div>
</li>
<li id="section-305">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-305">&#x00a7;</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><span class="hljs-built_in">exports</span>.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, {invert: @inverted, @guard, @isLoop} = {})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;condition&#x27;</span>, <span class="hljs-string">&#x27;guard&#x27;</span>, <span class="hljs-string">&#x27;body&#x27;</span>]
isStatement: YES
makeReturn: <span class="hljs-function"><span class="hljs-params">(results, mark)</span> -&gt;</span>
<span class="hljs-keyword">return</span> super(results, mark) <span class="hljs-keyword">if</span> results
@returns = <span class="hljs-keyword">not</span> @jumps()
<span class="hljs-keyword">if</span> mark
@body.makeReturn(results, mark) <span class="hljs-keyword">if</span> @returns
<span class="hljs-keyword">return</span>
this
addBody: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
this
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-306">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-306">&#x00a7;</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">&#x27;&#x27;</span>
{body} = this
<span class="hljs-keyword">if</span> body.isEmpty()
body = @makeCode <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> @returns
body.makeReturn rvar = o.scope.freeVariable <span class="hljs-string">&#x27;results&#x27;</span>
set = <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n&quot;</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">&quot;continue&quot;</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">&quot;\n&quot;</span>), (body.compileToFragments o, LEVEL_TOP), @makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>&quot;</span>)
answer = [].concat @makeCode(set + @tab + <span class="hljs-string">&quot;while (&quot;</span>), @processedCondition().compileToFragments(o, LEVEL_PAREN),
@makeCode(<span class="hljs-string">&quot;) {&quot;</span>), body, @makeCode(<span class="hljs-string">&quot;}&quot;</span>)
<span class="hljs-keyword">if</span> @returns
answer.push @makeCode <span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;&quot;</span>
answer
processedCondition: <span class="hljs-function">-&gt;</span>
@processedConditionCache ?= <span class="hljs-keyword">if</span> @inverted <span class="hljs-keyword">then</span> @condition.invert() <span class="hljs-keyword">else</span> @condition
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;WhileStatement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
test: @condition.ast o, LEVEL_PAREN
body: @body.ast o, LEVEL_TOP
guard: @guard?.ast(o) ? <span class="hljs-literal">null</span>
inverted: !!@inverted
postfix: !!@postfix
loop: !!@isLoop</pre></div></div>
</li>
<li id="section-307">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-307">&#x00a7;</a>
</div>
<h3 id="op">Op</h3>
</div>
</li>
<li id="section-308">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-308">&#x00a7;</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><span class="hljs-built_in">exports</span>.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, {@invertOperator, @originalOperator = op} = {})</span> -&gt;</span>
super()
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;new&#x27;</span>
<span class="hljs-keyword">if</span> ((firstCall = unwrapped = first.unwrap()) <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">or</span> (firstCall = unwrapped.base) <span class="hljs-keyword">instanceof</span> Call) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> firstCall.<span class="hljs-keyword">do</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> firstCall.isNew
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Value firstCall.newInstance(), <span class="hljs-keyword">if</span> firstCall <span class="hljs-keyword">is</span> unwrapped <span class="hljs-keyword">then</span> [] <span class="hljs-keyword">else</span> unwrapped.properties
first = <span class="hljs-keyword">new</span> Parens first <span class="hljs-keyword">unless</span> first <span class="hljs-keyword">instanceof</span> Parens <span class="hljs-keyword">or</span> first.unwrap() <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">or</span> first.hasProperties?()
call = <span class="hljs-keyword">new</span> Call first, []
call.locationData = @locationData
call.isNew = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span> call
@operator = CONVERSIONS[op] <span class="hljs-keyword">or</span> op
@first = first
@second = second
@flip = !!flip
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;--&#x27;</span>, <span class="hljs-string">&#x27;++&#x27;</span>]
message = isUnassignable @first.unwrapAll().value
@first.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">return</span> this</pre></div></div>
</li>
<li id="section-309">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-309">&#x00a7;</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">&#x27;==&#x27;</span>: <span class="hljs-string">&#x27;===&#x27;</span>
<span class="hljs-string">&#x27;!=&#x27;</span>: <span class="hljs-string">&#x27;!==&#x27;</span>
<span class="hljs-string">&#x27;of&#x27;</span>: <span class="hljs-string">&#x27;in&#x27;</span>
<span class="hljs-string">&#x27;yieldfrom&#x27;</span>: <span class="hljs-string">&#x27;yield*&#x27;</span></pre></div></div>
</li>
<li id="section-310">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-310">&#x00a7;</a>
</div>
<p>The map of invertible operators.</p>
</div>
<div class="content"><div class='highlight'><pre> INVERSIONS =
<span class="hljs-string">&#x27;!==&#x27;</span>: <span class="hljs-string">&#x27;===&#x27;</span>
<span class="hljs-string">&#x27;===&#x27;</span>: <span class="hljs-string">&#x27;!==&#x27;</span>
children: [<span class="hljs-string">&#x27;first&#x27;</span>, <span class="hljs-string">&#x27;second&#x27;</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">&#x27;+&#x27;</span>, <span class="hljs-string">&#x27;-&#x27;</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">&#x27;await&#x27;</span>
isYield: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;yield&#x27;</span>, <span class="hljs-string">&#x27;yield*&#x27;</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-311">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-311">&#x00a7;</a>
</div>
<p>Am I capable of
<a href="https://docs.python.org/3/reference/expressions.html#not-in">Python-style comparison chaining</a>?</p>
</div>
<div class="content"><div class='highlight'><pre> isChainable: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;&lt;&#x27;</span>, <span class="hljs-string">&#x27;&gt;&#x27;</span>, <span class="hljs-string">&#x27;&gt;=&#x27;</span>, <span class="hljs-string">&#x27;&lt;=&#x27;</span>, <span class="hljs-string">&#x27;===&#x27;</span>, <span class="hljs-string">&#x27;!==&#x27;</span>]
isChain: <span class="hljs-function">-&gt;</span>
@isChainable() <span class="hljs-keyword">and</span> @first.isChainable()
invert: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isInOperator()
@invertOperator = <span class="hljs-string">&#x27;!&#x27;</span>
<span class="hljs-keyword">return</span> @
<span class="hljs-keyword">if</span> @isChain()
allInvertable = <span class="hljs-literal">yes</span>
curr = this
<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(this).invert() <span class="hljs-keyword">unless</span> allInvertable
curr = this
<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
this
<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()
this
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @second
<span class="hljs-keyword">new</span> Parens(this).invert()
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;!&#x27;</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">&#x27;!&#x27;</span>, <span class="hljs-string">&#x27;in&#x27;</span>, <span class="hljs-string">&#x27;instanceof&#x27;</span>]
fst
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Op <span class="hljs-string">&#x27;!&#x27;</span>, this
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;++&#x27;</span>, <span class="hljs-string">&#x27;--&#x27;</span>, <span class="hljs-string">&#x27;delete&#x27;</span>] <span class="hljs-keyword">and</span> unfoldSoak o, this, <span class="hljs-string">&#x27;first&#x27;</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
isInOperator: <span class="hljs-function">-&gt;</span>
@originalOperator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;in&#x27;</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @isInOperator()
inNode = <span class="hljs-keyword">new</span> In @first, @second
<span class="hljs-keyword">return</span> (<span class="hljs-keyword">if</span> @invertOperator <span class="hljs-keyword">then</span> inNode.invert() <span class="hljs-keyword">else</span> inNode).compileNode o
<span class="hljs-keyword">if</span> @invertOperator
@invertOperator = <span class="hljs-literal">null</span>
<span class="hljs-keyword">return</span> @invert().compileNode(o)
<span class="hljs-keyword">return</span> Op::generateDo(@first).compileNode o <span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;do&#x27;</span>
isChain = @isChain()</pre></div></div>
</li>
<li id="section-312">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-312">&#x00a7;</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
@checkDeleteOperand o
<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">&#x27;?&#x27;</span> <span class="hljs-keyword">then</span> @compileExistence o, @second.isDefaultValue
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;//&#x27;</span> <span class="hljs-keyword">then</span> @compileFloorDivision o
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;%%&#x27;</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">&quot; <span class="hljs-subst">#{@operator}</span> &quot;</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-313">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-313">&#x00a7;</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">&#x27;console.log 50 &lt; 65 &gt; 10&#x27;</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">&quot; <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @invert <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&amp;&amp;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;||&#x27;</span>}</span> &quot;</span>),
(shared.compileToFragments o), @makeCode(<span class="hljs-string">&quot; <span class="hljs-subst">#{@operator}</span> &quot;</span>), (@second.compileToFragments o, LEVEL_OP)
@wrapInParentheses fragments</pre></div></div>
</li>
<li id="section-314">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-314">&#x00a7;</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">&#x27;ref&#x27;</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">&#x27;if&#x27;</span>).addElse(@second).compileToFragments o</pre></div></div>
</li>
<li id="section-315">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-315">&#x00a7;</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">&#x27;!&#x27;</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 this).compileToFragments o
plusMinus = op <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;+&#x27;</span>, <span class="hljs-string">&#x27;-&#x27;</span>]
parts.push [@makeCode(<span class="hljs-string">&#x27; &#x27;</span>)] <span class="hljs-keyword">if</span> op <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;typeof&#x27;</span>, <span class="hljs-string">&#x27;delete&#x27;</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
@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">&#x27;&#x27;</span>
compileContinuation: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
parts = []
op = @operator
@checkContinuation o <span class="hljs-keyword">unless</span> @isAwait()
<span class="hljs-keyword">if</span> <span class="hljs-string">&#x27;expression&#x27;</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">Object</span>.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">&quot;(&quot;</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
parts.push [@makeCode op]
parts.push [@makeCode <span class="hljs-string">&quot; &quot;</span>] <span class="hljs-keyword">if</span> @first.base?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;&#x27;</span>
parts.push @first.compileToFragments o, LEVEL_OP
parts.push [@makeCode <span class="hljs-string">&quot;)&quot;</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
@joinFragmentArrays parts, <span class="hljs-string">&#x27;&#x27;</span>
checkContinuation: <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">&quot;<span class="hljs-subst">#{@operator}</span> can only occur inside functions&quot;</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">&#x27;yield cannot occur inside bound (fat arrow) functions&#x27;</span>
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">&#x27;Math&#x27;</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">&#x27;floor&#x27;</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">&#x27;/&#x27;</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">&#x27;modulo&#x27;</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>
super idt, @constructor.name + <span class="hljs-string">&#x27; &#x27;</span> + @operator
checkDeleteOperand: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;delete&#x27;</span> <span class="hljs-keyword">and</span> o.scope.check(@first.unwrapAll().value)
@error <span class="hljs-string">&#x27;delete operand may not be argument or var&#x27;</span>
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkContinuation o <span class="hljs-keyword">if</span> @isYield()
@checkDeleteOperand o
super o
astType: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;AwaitExpression&#x27;</span> <span class="hljs-keyword">if</span> @isAwait()
<span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;YieldExpression&#x27;</span> <span class="hljs-keyword">if</span> @isYield()
<span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;ChainedComparison&#x27;</span> <span class="hljs-keyword">if</span> @isChain()
<span class="hljs-keyword">switch</span> @operator
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;||&#x27;</span>, <span class="hljs-string">&#x27;&amp;&amp;&#x27;</span>, <span class="hljs-string">&#x27;?&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;LogicalExpression&#x27;</span>
<span class="hljs-keyword">when</span> <span class="hljs-string">&#x27;++&#x27;</span>, <span class="hljs-string">&#x27;--&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;UpdateExpression&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> @isUnary() <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;UnaryExpression&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;BinaryExpression&#x27;</span>
operatorAst: <span class="hljs-function">-&gt;</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @invertOperator <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{@invertOperator}</span> &quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span><span class="hljs-subst">#{@originalOperator}</span>&quot;</span>
chainAstProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
operators = [@operatorAst()]
operands = [@second]
currentOp = @first
<span class="hljs-keyword">loop</span>
operators.unshift currentOp.operatorAst()
operands.unshift currentOp.second
currentOp = currentOp.first
<span class="hljs-keyword">unless</span> currentOp.isChainable()
operands.unshift currentOp
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">return</span> {
operators
operands: (operand.ast(o, LEVEL_OP) <span class="hljs-keyword">for</span> operand <span class="hljs-keyword">in</span> operands)
}
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> @chainAstProperties(o) <span class="hljs-keyword">if</span> @isChain()
firstAst = @first.ast o, LEVEL_OP
secondAst = @second?.ast o, LEVEL_OP
operatorAst = @operatorAst()
<span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> @isUnary()
argument =
<span class="hljs-keyword">if</span> @isYield() <span class="hljs-keyword">and</span> @first.unwrap().value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-literal">null</span>
<span class="hljs-keyword">else</span>
firstAst
<span class="hljs-keyword">return</span> {argument} <span class="hljs-keyword">if</span> @isAwait()
<span class="hljs-keyword">return</span> {
argument
delegate: @operator <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;yield*&#x27;</span>
} <span class="hljs-keyword">if</span> @isYield()
<span class="hljs-keyword">return</span> {
argument
operator: operatorAst
prefix: !@flip
}
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span>
left: firstAst
right: secondAst
operator: operatorAst</pre></div></div>
</li>
<li id="section-316">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-316">&#x00a7;</a>
</div>
<h3 id="in">In</h3>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;object&#x27;</span>, <span class="hljs-string">&#x27;array&#x27;</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-317">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-317">&#x00a7;</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">&#x27; !== &#x27;</span>, <span class="hljs-string">&#x27; &amp;&amp; &#x27;</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">&#x27; === &#x27;</span>, <span class="hljs-string">&#x27; || &#x27;</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">&#x27;indexOf&#x27;</span>, o) + <span class="hljs-string">&quot;.call(&quot;</span>), @array.compileToFragments(o, LEVEL_LIST),
@makeCode(<span class="hljs-string">&quot;, &quot;</span>), ref, @makeCode(<span class="hljs-string">&quot;) &quot;</span> + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&lt; 0&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&gt;= 0&#x27;</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">&#x27;, &#x27;</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>
super idt, @constructor.name + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;!&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span></pre></div></div>
</li>
<li id="section-318">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-318">&#x00a7;</a>
</div>
<h3 id="try">Try</h3>
</div>
</li>
<li id="section-319">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-319">&#x00a7;</a>
</div>
<p>A classic <em>try/catch/finally</em> block.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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, @catch, @ensure, @finallyTag)</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;attempt&#x27;</span>, <span class="hljs-string">&#x27;catch&#x27;</span>, <span class="hljs-string">&#x27;ensure&#x27;</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> @catch?.jumps(o)
makeReturn: <span class="hljs-function"><span class="hljs-params">(results, mark)</span> -&gt;</span>
<span class="hljs-keyword">if</span> mark
@attempt?.makeReturn results, mark
@catch?.makeReturn results, mark
<span class="hljs-keyword">return</span>
@attempt = @attempt.makeReturn results <span class="hljs-keyword">if</span> @attempt
@catch = @catch .makeReturn results <span class="hljs-keyword">if</span> @catch
this</pre></div></div>
</li>
<li id="section-320">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-320">&#x00a7;</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>
originalIndent = o.indent
o.indent += TAB
tryPart = @attempt.compileToFragments o, LEVEL_TOP
catchPart = <span class="hljs-keyword">if</span> @catch
@catch.compileToFragments merge(o, indent: originalIndent), LEVEL_TOP
<span class="hljs-keyword">else</span> <span class="hljs-keyword">unless</span> @ensure <span class="hljs-keyword">or</span> @catch
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">&#x27;error&#x27;</span>, reserve: <span class="hljs-literal">no</span>
[@makeCode(<span class="hljs-string">&quot; catch (<span class="hljs-subst">#{generatedErrorVariableName}</span>) {}&quot;</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">&quot; finally {\n&quot;</span>), @ensure.compileToFragments(o, LEVEL_TOP),
@makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>}&quot;</span>)) <span class="hljs-keyword">else</span> []
[].concat @makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span>try {\n&quot;</span>),
tryPart,
@makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>}&quot;</span>), catchPart, ensurePart
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;TryStatement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
block: @attempt.ast o, LEVEL_TOP
handler: @catch?.ast(o) ? <span class="hljs-literal">null</span>
finalizer:
<span class="hljs-keyword">if</span> @ensure?
<span class="hljs-built_in">Object</span>.assign @ensure.ast(o, LEVEL_TOP),</pre></div></div>
</li>
<li id="section-321">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-321">&#x00a7;</a>
</div>
<p>Include <code>finally</code> keyword in location data.</p>
</div>
<div class="content"><div class='highlight'><pre> mergeAstLocationData(
jisonLocationDataToAstLocationData(@finallyTag.locationData),
@ensure.astLocationData()
)
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span>
<span class="hljs-built_in">exports</span>.Catch = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Catch</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@recovery, @errorVariable)</span> -&gt;</span>
super()
@errorVariable?.unwrap().propagateLhs? <span class="hljs-literal">yes</span>
children: [<span class="hljs-string">&#x27;recovery&#x27;</span>, <span class="hljs-string">&#x27;errorVariable&#x27;</span>]
isStatement: YES
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> @recovery.jumps o
makeReturn: <span class="hljs-function"><span class="hljs-params">(results, mark)</span> -&gt;</span>
ret = @recovery.makeReturn results, mark
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> mark
@recovery = ret
this
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.indent += TAB
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">&#x27;error&#x27;</span>, reserve: <span class="hljs-literal">no</span>
placeholder = <span class="hljs-keyword">new</span> IdentifierLiteral generatedErrorVariableName
@checkUnassignable()
<span class="hljs-keyword">if</span> @errorVariable
@recovery.unshift <span class="hljs-keyword">new</span> Assign @errorVariable, placeholder
[].concat @makeCode(<span class="hljs-string">&quot; catch (&quot;</span>), placeholder.compileToFragments(o), @makeCode(<span class="hljs-string">&quot;) {\n&quot;</span>),
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>}&quot;</span>)
checkUnassignable: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @errorVariable
message = isUnassignable @errorVariable.unwrapAll().value
@errorVariable.error message <span class="hljs-keyword">if</span> message
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkUnassignable()
@errorVariable?.eachName (name) -&gt;
alreadyDeclared = o.scope.find name.value
name.isDeclaration = <span class="hljs-keyword">not</span> alreadyDeclared
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;CatchClause&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
param: @errorVariable?.ast(o) ? <span class="hljs-literal">null</span>
body: @recovery.ast o, LEVEL_TOP</pre></div></div>
</li>
<li id="section-322">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-322">&#x00a7;</a>
</div>
<h3 id="throw">Throw</h3>
</div>
</li>
<li id="section-323">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-323">&#x00a7;</a>
</div>
<p>Simple node to throw an exception.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;expression&#x27;</span>]
isStatement: YES
jumps: NO</pre></div></div>
</li>
<li id="section-324">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-324">&#x00a7;</a>
</div>
<p>A <strong>Throw</strong> is already a return, of sorts…</p>
</div>
<div class="content"><div class='highlight'><pre> makeReturn: THIS
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
fragments = @expression.compileToFragments o, LEVEL_LIST
unshiftAfterComments fragments, @makeCode <span class="hljs-string">&#x27;throw &#x27;</span>
fragments.unshift @makeCode @tab
fragments.push @makeCode <span class="hljs-string">&#x27;;&#x27;</span>
fragments
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;ThrowStatement&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
argument: @expression.ast o, LEVEL_LIST</pre></div></div>
</li>
<li id="section-325">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-325">&#x00a7;</a>
</div>
<h3 id="existence">Existence</h3>
</div>
</li>
<li id="section-326">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-326">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
@comparisonTarget = <span class="hljs-keyword">if</span> onlyNotUndefined <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;undefined&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;null&#x27;</span>
salvagedComments = []
@expression.traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> -&gt;</span>
<span class="hljs-keyword">if</span> child.comments
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> child.comments
salvagedComments.push comment <span class="hljs-keyword">unless</span> comment <span class="hljs-keyword">in</span> salvagedComments
<span class="hljs-keyword">delete</span> child.comments
attachCommentsToNode salvagedComments, @
moveComments @expression, @
children: [<span class="hljs-string">&#x27;expression&#x27;</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">&#x27;===&#x27;</span>, <span class="hljs-string">&#x27;||&#x27;</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">&#x27;!==&#x27;</span>, <span class="hljs-string">&#x27;&amp;&amp;&#x27;</span>]
code = <span class="hljs-string">&quot;typeof <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> \&quot;undefined\&quot;&quot;</span> + <span class="hljs-keyword">if</span> @comparisonTarget <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;undefined&#x27;</span> <span class="hljs-keyword">then</span> <span class="hljs-string">&quot; <span class="hljs-subst">#{cnj}</span> <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> <span class="hljs-subst">#{@comparisonTarget}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-keyword">else</span></pre></div></div>
</li>
<li id="section-327">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-327">&#x00a7;</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">&#x27;null&#x27;</span>
<span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;==&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;!=&#x27;</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">&#x27;===&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;!==&#x27;</span>
code = <span class="hljs-string">&quot;<span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> <span class="hljs-subst">#{@comparisonTarget}</span>&quot;</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">&quot;(<span class="hljs-subst">#{code}</span>)&quot;</span>)]
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;UnaryExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
argument: @expression.ast o
operator: <span class="hljs-string">&#x27;?&#x27;</span>
prefix: <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-328">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-328">&#x00a7;</a>
</div>
<h3 id="parens">Parens</h3>
</div>
</li>
<li id="section-329">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-329">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;body&#x27;</span>]
unwrap: <span class="hljs-function">-&gt;</span> @body
shouldCache: <span class="hljs-function">-&gt;</span> @body.shouldCache()
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
expr = @body.unwrap()</pre></div></div>
</li>
<li id="section-330">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-330">&#x00a7;</a>
</div>
<p>If these parentheses are wrapping an <code>IdentifierLiteral</code> followed by a
block comment, output the parentheses (or put another way, dont optimize
away these redundant parentheses). This is because Flow requires
parentheses in certain circumstances to distinguish identifiers followed
by comment-based type annotations from JavaScript labels.</p>
</div>
<div class="content"><div class='highlight'><pre> shouldWrapComment = expr.comments?.some(
<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.unshift <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> comment.newLine)
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isAtomic() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @jsxAttribute <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> shouldWrapComment
expr.front = @front
<span class="hljs-keyword">return</span> expr.compileToFragments o
fragments = expr.compileToFragments o, LEVEL_PAREN
bare = o.level &lt; LEVEL_OP <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> shouldWrapComment <span class="hljs-keyword">and</span> (
expr <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> expr.isInOperator() <span class="hljs-keyword">or</span> expr.unwrap() <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">or</span>
(expr <span class="hljs-keyword">instanceof</span> For <span class="hljs-keyword">and</span> expr.returns)
) <span class="hljs-keyword">and</span> (o.level &lt; LEVEL_COND <span class="hljs-keyword">or</span> fragments.length &lt;= <span class="hljs-number">3</span>)
<span class="hljs-keyword">return</span> @wrapInBraces fragments <span class="hljs-keyword">if</span> @jsxAttribute
<span class="hljs-keyword">if</span> bare <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInParentheses fragments
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> @body.unwrap().ast o, LEVEL_PAREN</pre></div></div>
</li>
<li id="section-331">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-331">&#x00a7;</a>
</div>
<h3 id="stringwithinterpolations">StringWithInterpolations</h3>
</div>
<div class="content"><div class='highlight'><pre>
<span class="hljs-built_in">exports</span>.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, {@quote, @startQuote, @jsxAttribute} = {})</span> -&gt;</span>
super()
@fromStringLiteral: <span class="hljs-function"><span class="hljs-params">(stringLiteral)</span> -&gt;</span>
updatedString = stringLiteral.withoutQuotesInLocationData()
updatedStringValue = <span class="hljs-keyword">new</span> Value(updatedString).withLocationDataFrom updatedString
<span class="hljs-keyword">new</span> StringWithInterpolations Block.wrap([updatedStringValue]), quote: stringLiteral.quote, jsxAttribute: stringLiteral.jsxAttribute
.withLocationDataFrom stringLiteral
children: [<span class="hljs-string">&#x27;body&#x27;</span>]</pre></div></div>
</li>
<li id="section-332">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-332">&#x00a7;</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> this
shouldCache: <span class="hljs-function">-&gt;</span> @body.shouldCache()
extractElements: <span class="hljs-function"><span class="hljs-params">(o, {includeInterpolationWrappers, isJsx} = {})</span> -&gt;</span></pre></div></div>
</li>
<li id="section-333">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-333">&#x00a7;</a>
</div>
<p>Assumes that <code>expr</code> is <code>Block</code></p>
</div>
<div class="content"><div class='highlight'><pre> expr = @body.unwrap()
elements = []
salvagedComments = []
expr.traverseChildren <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">if</span> node.comments
salvagedComments.push node.comments...
<span class="hljs-keyword">delete</span> node.comments
elements.push node
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Interpolation
<span class="hljs-keyword">if</span> salvagedComments.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> salvagedComments
comment.unshift = <span class="hljs-literal">yes</span>
comment.newLine = <span class="hljs-literal">yes</span>
attachCommentsToNode salvagedComments, node
<span class="hljs-keyword">if</span> (unwrapped = node.expression?.unwrapAll()) <span class="hljs-keyword">instanceof</span> PassthroughLiteral <span class="hljs-keyword">and</span> unwrapped.generated <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (isJsx <span class="hljs-keyword">and</span> o.compiling)
<span class="hljs-keyword">if</span> o.compiling
commentPlaceholder = <span class="hljs-keyword">new</span> StringLiteral(<span class="hljs-string">&#x27;&#x27;</span>).withLocationDataFrom node
commentPlaceholder.comments = unwrapped.comments
(commentPlaceholder.comments ?= []).push node.comments... <span class="hljs-keyword">if</span> node.comments
elements.push <span class="hljs-keyword">new</span> Value commentPlaceholder
<span class="hljs-keyword">else</span>
empty = <span class="hljs-keyword">new</span> Interpolation().withLocationDataFrom node
empty.comments = node.comments
elements.push empty
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.expression <span class="hljs-keyword">or</span> includeInterpolationWrappers
(node.expression?.comments ?= []).push node.comments... <span class="hljs-keyword">if</span> node.comments
elements.push <span class="hljs-keyword">if</span> includeInterpolationWrappers <span class="hljs-keyword">then</span> node <span class="hljs-keyword">else</span> node.expression
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.comments</pre></div></div>
</li>
<li id="section-334">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-334">&#x00a7;</a>
</div>
<p>This node is getting discarded, but salvage its comments.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> elements.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> elements[elements.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> StringLiteral
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
comment.unshift = <span class="hljs-literal">no</span>
comment.newLine = <span class="hljs-literal">yes</span>
attachCommentsToNode node.comments, elements[elements.length - <span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>
salvagedComments.push node.comments...
<span class="hljs-keyword">delete</span> node.comments
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
elements
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@comments ?= @startQuote?.comments
<span class="hljs-keyword">if</span> @jsxAttribute
wrapped = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> StringWithInterpolations @body
wrapped.jsxAttribute = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">return</span> wrapped.compileNode o
elements = @extractElements o, isJsx: @jsx
fragments = []
fragments.push @makeCode <span class="hljs-string">&#x27;`&#x27;</span> <span class="hljs-keyword">unless</span> @jsx
<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
unquotedElementValue = <span class="hljs-keyword">if</span> @jsx <span class="hljs-keyword">then</span> element.unquotedValueForJSX <span class="hljs-keyword">else</span> element.unquotedValueForTemplateLiteral
fragments.push @makeCode unquotedElementValue
<span class="hljs-keyword">else</span>
fragments.push @makeCode <span class="hljs-string">&#x27;$&#x27;</span> <span class="hljs-keyword">unless</span> @jsx
code = element.compileToFragments(o, LEVEL_PAREN)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @isNestedTag(element) <span class="hljs-keyword">or</span>
code.some(<span class="hljs-function"><span class="hljs-params">(fragment)</span> -&gt;</span> fragment.comments?.some(<span class="hljs-function"><span class="hljs-params">(comment)</span> -&gt;</span> comment.here <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span>))
code = @wrapInBraces code</pre></div></div>
</li>
<li id="section-335">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-335">&#x00a7;</a>
</div>
<p>Flag the <code>{</code> and <code>}</code> fragments as having been generated by this
<code>StringWithInterpolations</code> node, so that <code>compileComments</code> knows
to treat them as bounds. But the braces are unnecessary if all of
the enclosed comments are <code>/* */</code> comments. Dont trust
<code>fragment.type</code>, which can report minified variable names when
this compiler is minified.</p>
</div>
<div class="content"><div class='highlight'><pre> code[<span class="hljs-number">0</span>].isStringWithInterpolations = <span class="hljs-literal">yes</span>
code[code.length - <span class="hljs-number">1</span>].isStringWithInterpolations = <span class="hljs-literal">yes</span>
fragments.push code...
fragments.push @makeCode <span class="hljs-string">&#x27;`&#x27;</span> <span class="hljs-keyword">unless</span> @jsx
fragments
isNestedTag: <span class="hljs-function"><span class="hljs-params">(element)</span> -&gt;</span>
call = element.unwrapAll?()
@jsx <span class="hljs-keyword">and</span> call <span class="hljs-keyword">instanceof</span> JSXElement
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;TemplateLiteral&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
elements = @extractElements o, includeInterpolationWrappers: <span class="hljs-literal">yes</span>
[..., last] = elements
quasis = []
expressions = []
<span class="hljs-keyword">for</span> element, index <span class="hljs-keyword">in</span> elements
<span class="hljs-keyword">if</span> element <span class="hljs-keyword">instanceof</span> StringLiteral
quasis.push <span class="hljs-keyword">new</span> TemplateElement(
element.originalValue
tail: element <span class="hljs-keyword">is</span> last
).withLocationDataFrom(element).ast o
<span class="hljs-keyword">else</span> <span class="hljs-comment"># Interpolation</span>
{expression} = element
node =
<span class="hljs-keyword">unless</span> expression?
emptyInterpolation = <span class="hljs-keyword">new</span> EmptyInterpolation()
emptyInterpolation.locationData = emptyExpressionLocationData {
interpolationNode: element
openingBrace: <span class="hljs-string">&#x27;#{&#x27;</span>
closingBrace: <span class="hljs-string">&#x27;}&#x27;</span>
}
emptyInterpolation
<span class="hljs-keyword">else</span>
expression.unwrapAll()
expressions.push astAsBlockIfNeeded node, o
{expressions, quasis, @quote}
<span class="hljs-built_in">exports</span>.TemplateElement = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TemplateElement</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@value, {@tail} = {})</span> -&gt;</span>
super()
astProperties: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span>
value:
raw: @value
tail: !!@tail
<span class="hljs-built_in">exports</span>.Interpolation = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Interpolation</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>
super()
children: [<span class="hljs-string">&#x27;expression&#x27;</span>]</pre></div></div>
</li>
<li id="section-336">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-336">&#x00a7;</a>
</div>
<p>Represents the contents of an empty interpolation (e.g. <code>#{}</code>).
Only used during AST generation.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.EmptyInterpolation = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmptyInterpolation</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function">-&gt;</span>
super()</pre></div></div>
</li>
<li id="section-337">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-337">&#x00a7;</a>
</div>
<h3 id="for">For</h3>
</div>
</li>
<li id="section-338">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-338">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
@addBody body
@addSource source
children: [<span class="hljs-string">&#x27;body&#x27;</span>, <span class="hljs-string">&#x27;source&#x27;</span>, <span class="hljs-string">&#x27;guard&#x27;</span>, <span class="hljs-string">&#x27;step&#x27;</span>]
isAwait: <span class="hljs-function">-&gt;</span> @await ? <span class="hljs-literal">no</span>
addBody: <span class="hljs-function"><span class="hljs-params">(body)</span> -&gt;</span>
@body = Block.wrap [body]
{expressions} = @body
<span class="hljs-keyword">if</span> expressions.length
@body.locationData ?= mergeLocationData expressions[<span class="hljs-number">0</span>].locationData, expressions[expressions.length - <span class="hljs-number">1</span>].locationData
this
addSource: <span class="hljs-function"><span class="hljs-params">(source)</span> -&gt;</span>
{@source = <span class="hljs-literal">no</span>} = source
attribs = [<span class="hljs-string">&quot;name&quot;</span>, <span class="hljs-string">&quot;index&quot;</span>, <span class="hljs-string">&quot;guard&quot;</span>, <span class="hljs-string">&quot;step&quot;</span>, <span class="hljs-string">&quot;own&quot;</span>, <span class="hljs-string">&quot;ownTag&quot;</span>, <span class="hljs-string">&quot;await&quot;</span>, <span class="hljs-string">&quot;awaitTag&quot;</span>, <span class="hljs-string">&quot;object&quot;</span>, <span class="hljs-string">&quot;from&quot;</span>]
@[attr] = source[attr] ? @[attr] <span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> attribs
<span class="hljs-keyword">return</span> this <span class="hljs-keyword">unless</span> @source
@index.error <span class="hljs-string">&#x27;cannot use index with for-from&#x27;</span> <span class="hljs-keyword">if</span> @from <span class="hljs-keyword">and</span> @index
@ownTag.error <span class="hljs-string">&quot;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">&#x27;from&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;in&#x27;</span>}</span>&quot;</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">&#x27;index cannot be a pattern matching expression&#x27;</span> <span class="hljs-keyword">if</span> @index?.isArray?() <span class="hljs-keyword">or</span> @index?.isObject?()
@awaitTag.error <span class="hljs-string">&#x27;await must be used with for-from&#x27;</span> <span class="hljs-keyword">if</span> @await <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @from
@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
@name.unwrap().propagateLhs?(<span class="hljs-literal">yes</span>) <span class="hljs-keyword">if</span> @pattern
@index.error <span class="hljs-string">&#x27;indexes do not apply to range loops&#x27;</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @index
@name.error <span class="hljs-string">&#x27;cannot pattern match over range loops&#x27;</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @pattern
@returns = <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-339">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-339">&#x00a7;</a>
</div>
<p>Move up any comments in the “<code>for</code> line”, i.e. the line of code with <code>for</code>,
from any child nodes of that line up to the <code>for</code> node itself so that these
comments get output, and get output above the <code>for</code> loop.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> attribute <span class="hljs-keyword">in</span> [<span class="hljs-string">&#x27;source&#x27;</span>, <span class="hljs-string">&#x27;guard&#x27;</span>, <span class="hljs-string">&#x27;step&#x27;</span>, <span class="hljs-string">&#x27;name&#x27;</span>, <span class="hljs-string">&#x27;index&#x27;</span>] <span class="hljs-keyword">when</span> @[attribute]
@[attribute].traverseChildren <span class="hljs-literal">yes</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> =&gt;</span>
<span class="hljs-keyword">if</span> node.comments</pre></div></div>
</li>
<li id="section-340">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-340">&#x00a7;</a>
</div>
<p>These comments are buried pretty deeply, so if they happen to be
trailing comments the line they trail will be unrecognizable when
were done compiling this <code>for</code> loop; so just shift them up to
output above the <code>for</code> line.</p>
</div>
<div class="content"><div class='highlight'><pre> comment.newLine = comment.unshift = <span class="hljs-literal">yes</span> <span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
moveComments node, @[attribute]
moveComments @[attribute], @
this</pre></div></div>
</li>
<li id="section-341">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-341">&#x00a7;</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">&#x27;results&#x27;</span> <span class="hljs-keyword">if</span> @returns
<span class="hljs-keyword">if</span> @from
ivar = scope.freeVariable <span class="hljs-string">&#x27;x&#x27;</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">&#x27;i&#x27;</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">&quot;<span class="hljs-subst">#{kvar}</span> = &quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;&quot;</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 = parseNumber stepVar <span class="hljs-keyword">if</span> @step.isNumber()
name = ivar <span class="hljs-keyword">if</span> @pattern
varPart = <span class="hljs-string">&#x27;&#x27;</span>
guardPart = <span class="hljs-string">&#x27;&#x27;</span>
defPart = <span class="hljs-string">&#x27;&#x27;</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> <span class="hljs-keyword">not</span> @from <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">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{ref = scope.freeVariable <span class="hljs-string">&#x27;ref&#x27;</span>}</span> = <span class="hljs-subst">#{svar}</span>;\n&quot;</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">&quot;<span class="hljs-subst">#{name}</span> = <span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]&quot;</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">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{step}</span>;\n&quot;</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">&#x27;len&#x27;</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">&quot;<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&quot;</span>
declareDown = <span class="hljs-string">&quot;<span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{svar}</span>.length - 1&quot;</span>
compare = <span class="hljs-string">&quot;<span class="hljs-subst">#{ivar}</span> &lt; <span class="hljs-subst">#{lvar}</span>&quot;</span>
compareDown = <span class="hljs-string">&quot;<span class="hljs-subst">#{ivar}</span> &gt;= 0&quot;</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">&quot;<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? <span class="hljs-subst">#{compare}</span> : <span class="hljs-subst">#{compareDown}</span>&quot;</span>
declare = <span class="hljs-string">&quot;(<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? (<span class="hljs-subst">#{declare}</span>) : <span class="hljs-subst">#{declareDown}</span>)&quot;</span>
increment = <span class="hljs-string">&quot;<span class="hljs-subst">#{ivar}</span> += <span class="hljs-subst">#{stepVar}</span>&quot;</span>
<span class="hljs-keyword">else</span>
increment = <span class="hljs-string">&quot;<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">&quot;++<span class="hljs-subst">#{ivar}</span>&quot;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;<span class="hljs-subst">#{ivar}</span>++&quot;</span>}</span>&quot;</span>
forPartFragments = [@makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{declare}</span>; <span class="hljs-subst">#{compare}</span>; <span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{increment}</span>&quot;</span>)]
<span class="hljs-keyword">if</span> @returns
resultPart = <span class="hljs-string">&quot;<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n&quot;</span>
returnResult = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;&quot;</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">&quot;continue&quot;</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">&quot;<span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]&quot;</span>
varPart = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{idt1}</span><span class="hljs-subst">#{namePart}</span>;&quot;</span> <span class="hljs-keyword">if</span> namePart
<span class="hljs-keyword">if</span> @object
forPartFragments = [@makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{kvar}</span> in <span class="hljs-subst">#{svar}</span>&quot;</span>)]
guardPart = <span class="hljs-string">&quot;\n<span class="hljs-subst">#{idt1}</span>if (!<span class="hljs-subst">#{utility <span class="hljs-string">&#x27;hasProp&#x27;</span>, o}</span>.call(<span class="hljs-subst">#{svar}</span>, <span class="hljs-subst">#{kvar}</span>)) continue;&quot;</span> <span class="hljs-keyword">if</span> @own
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @from
<span class="hljs-keyword">if</span> @await
forPartFragments = <span class="hljs-keyword">new</span> Op <span class="hljs-string">&#x27;await&#x27;</span>, <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Literal <span class="hljs-string">&quot;<span class="hljs-subst">#{kvar}</span> of <span class="hljs-subst">#{svar}</span>&quot;</span>
forPartFragments = forPartFragments.compileToFragments o, LEVEL_TOP
<span class="hljs-keyword">else</span>
forPartFragments = [@makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{kvar}</span> of <span class="hljs-subst">#{svar}</span>&quot;</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">&#x27;\n&#x27;</span>), bodyFragments, @makeCode(<span class="hljs-string">&#x27;\n&#x27;</span>)
fragments = [@makeCode(defPart)]
fragments.push @makeCode(resultPart) <span class="hljs-keyword">if</span> resultPart
forCode = <span class="hljs-keyword">if</span> @await <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;for &#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;for (&#x27;</span>
forClose = <span class="hljs-keyword">if</span> @await <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;)&#x27;</span>
fragments = fragments.concat @makeCode(@tab), @makeCode( forCode),
forPartFragments, @makeCode(<span class="hljs-string">&quot;<span class="hljs-subst">#{forClose}</span> {<span class="hljs-subst">#{guardPart}</span><span class="hljs-subst">#{varPart}</span>&quot;</span>), bodyFragments,
@makeCode(@tab), @makeCode(<span class="hljs-string">&#x27;}&#x27;</span>)
fragments.push @makeCode(returnResult) <span class="hljs-keyword">if</span> returnResult
fragments
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-function"> <span class="hljs-title">addToScope</span> = <span class="hljs-params">(name)</span> -&gt;</span>
alreadyDeclared = o.scope.find name.value
name.isDeclaration = <span class="hljs-keyword">not</span> alreadyDeclared
@name?.eachName addToScope, checkAssignability: <span class="hljs-literal">no</span>
@index?.eachName addToScope, checkAssignability: <span class="hljs-literal">no</span>
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;For&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
source: @source?.ast o
body: @body.ast o, LEVEL_TOP
guard: @guard?.ast(o) ? <span class="hljs-literal">null</span>
name: @name?.ast(o) ? <span class="hljs-literal">null</span>
index: @index?.ast(o) ? <span class="hljs-literal">null</span>
step: @step?.ast(o) ? <span class="hljs-literal">null</span>
postfix: !!@postfix
own: !!@own
await: !!@await
style: <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> @from <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;from&#x27;</span>
<span class="hljs-keyword">when</span> @object <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;of&#x27;</span>
<span class="hljs-keyword">when</span> @name <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;in&#x27;</span>
<span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;range&#x27;</span></pre></div></div>
</li>
<li id="section-342">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-342">&#x00a7;</a>
</div>
<h3 id="switch">Switch</h3>
</div>
</li>
<li id="section-343">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-343">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
children: [<span class="hljs-string">&#x27;subject&#x27;</span>, <span class="hljs-string">&#x27;cases&#x27;</span>, <span class="hljs-string">&#x27;otherwise&#x27;</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> {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">(results, mark)</span> -&gt;</span>
block.makeReturn(results, mark) <span class="hljs-keyword">for</span> {block} <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">&#x27;void 0&#x27;</span>] <span class="hljs-keyword">if</span> results
@otherwise?.makeReturn results, mark
this
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">&quot;switch (&quot;</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">&quot;false&quot;</span>),
@makeCode(<span class="hljs-string">&quot;) {\n&quot;</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">&quot;case &quot;</span>), cond.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">&quot;:\n&quot;</span>)
fragments = fragments.concat body, @makeCode(<span class="hljs-string">&#x27;\n&#x27;</span>) <span class="hljs-keyword">if</span> (body = block.compileToFragments o, LEVEL_TOP).length &gt; <span class="hljs-number">0</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> @cases.length - <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @otherwise
expr = @lastNode block.expressions
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">or</span> expr <span class="hljs-keyword">instanceof</span> Throw <span class="hljs-keyword">or</span> (expr <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> expr.jumps() <span class="hljs-keyword">and</span> expr.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">&#x27;debugger&#x27;</span>)
fragments.push cond.makeCode(idt2 + <span class="hljs-string">&#x27;break;\n&#x27;</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">&quot;default:\n&quot;</span>), (@otherwise.compileToFragments o, LEVEL_TOP)..., @makeCode(<span class="hljs-string">&quot;\n&quot;</span>)
fragments.push @makeCode @tab + <span class="hljs-string">&#x27;}&#x27;</span>
fragments
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;SwitchStatement&#x27;</span>
casesAst: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
cases = []
<span class="hljs-keyword">for</span> kase, caseIndex <span class="hljs-keyword">in</span> @cases
{conditions: tests, block: consequent} = kase
tests = flatten [tests]
lastTestIndex = tests.length - <span class="hljs-number">1</span>
<span class="hljs-keyword">for</span> test, testIndex <span class="hljs-keyword">in</span> tests
testConsequent =
<span class="hljs-keyword">if</span> testIndex <span class="hljs-keyword">is</span> lastTestIndex
consequent
<span class="hljs-keyword">else</span>
<span class="hljs-literal">null</span>
caseLocationData = test.locationData
caseLocationData = mergeLocationData caseLocationData, testConsequent.expressions[testConsequent.expressions.length - <span class="hljs-number">1</span>].locationData <span class="hljs-keyword">if</span> testConsequent?.expressions.length
caseLocationData = mergeLocationData caseLocationData, kase.locationData, justLeading: <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> testIndex <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
caseLocationData = mergeLocationData caseLocationData, kase.locationData, justEnding: <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> testIndex <span class="hljs-keyword">is</span> lastTestIndex
cases.push <span class="hljs-keyword">new</span> SwitchCase(test, testConsequent, trailing: testIndex <span class="hljs-keyword">is</span> lastTestIndex).withLocationDataFrom locationData: caseLocationData
<span class="hljs-keyword">if</span> @otherwise?.expressions.length
cases.push <span class="hljs-keyword">new</span> SwitchCase(<span class="hljs-literal">null</span>, @otherwise).withLocationDataFrom @otherwise
kase.ast(o) <span class="hljs-keyword">for</span> kase <span class="hljs-keyword">in</span> cases
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
discriminant: @subject?.ast(o, LEVEL_PAREN) ? <span class="hljs-literal">null</span>
cases: @casesAst o
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SwitchCase</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@test, @block, {@trailing} = {})</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;test&#x27;</span>, <span class="hljs-string">&#x27;block&#x27;</span>]
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
test: @test?.ast(o, LEVEL_PAREN) ? <span class="hljs-literal">null</span>
consequent: @block?.ast(o, LEVEL_TOP).body ? []
trailing: !!@trailing
<span class="hljs-built_in">exports</span>.SwitchWhen = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SwitchWhen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@conditions, @block)</span> -&gt;</span>
super()
children: [<span class="hljs-string">&#x27;conditions&#x27;</span>, <span class="hljs-string">&#x27;block&#x27;</span>]</pre></div></div>
</li>
<li id="section-344">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-344">&#x00a7;</a>
</div>
<h3 id="if">If</h3>
</div>
</li>
<li id="section-345">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-345">&#x00a7;</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><span class="hljs-built_in">exports</span>.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>
super()
@elseBody = <span class="hljs-literal">null</span>
@isChain = <span class="hljs-literal">false</span>
{@soak, @postfix, @type} = options
moveComments @condition, @ <span class="hljs-keyword">if</span> @condition.comments
children: [<span class="hljs-string">&#x27;condition&#x27;</span>, <span class="hljs-string">&#x27;body&#x27;</span>, <span class="hljs-string">&#x27;elseBody&#x27;</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-346">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-346">&#x00a7;</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
@locationData = mergeLocationData @locationData, @elseBodyNode().locationData
<span class="hljs-keyword">else</span>
@isChain = elseBody <span class="hljs-keyword">instanceof</span> If
@elseBody = @ensureBlock elseBody
@elseBody.updateLocationDataIfMissing elseBody.locationData
@locationData = mergeLocationData @locationData, @elseBody.locationData <span class="hljs-keyword">if</span> @locationData? <span class="hljs-keyword">and</span> @elseBody.locationData?
this</pre></div></div>
</li>
<li id="section-347">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-347">&#x00a7;</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">(results, mark)</span> -&gt;</span>
<span class="hljs-keyword">if</span> mark
@body?.makeReturn results, mark
@elseBody?.makeReturn results, mark
<span class="hljs-keyword">return</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">&#x27;void 0&#x27;</span>] <span class="hljs-keyword">if</span> results
@body <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@body.makeReturn results]
@elseBody <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@elseBody.makeReturn results]
this
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-348">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-348">&#x00a7;</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">&#x27;chainChild&#x27;</span>
exeq = del o, <span class="hljs-string">&#x27;isExistentialEquals&#x27;</span>
<span class="hljs-keyword">if</span> exeq
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If(@processedCondition().invert(), @elseBodyNode(), type: <span class="hljs-string">&#x27;if&#x27;</span>).compileToFragments o
indent = o.indent + TAB
cond = @processedCondition().compileToFragments o, LEVEL_PAREN
body = @ensureBlock(@body).compileToFragments merge o, {indent}
ifPart = [].concat @makeCode(<span class="hljs-string">&quot;if (&quot;</span>), cond, @makeCode(<span class="hljs-string">&quot;) {\n&quot;</span>), body, @makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>}&quot;</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">&#x27; else &#x27;</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">&quot;{\n&quot;</span>), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode(<span class="hljs-string">&quot;\n<span class="hljs-subst">#{@tab}</span>}&quot;</span>)
answer</pre></div></div>
</li>
<li id="section-349">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-349">&#x00a7;</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 = @processedCondition().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">&#x27;void 0&#x27;</span>)]
fragments = cond.concat @makeCode(<span class="hljs-string">&quot; ? &quot;</span>), body, @makeCode(<span class="hljs-string">&quot; : &quot;</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> this
processedCondition: <span class="hljs-function">-&gt;</span>
@processedConditionCache ?= <span class="hljs-keyword">if</span> @type <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;unless&#x27;</span> <span class="hljs-keyword">then</span> @condition.invert() <span class="hljs-keyword">else</span> @condition
isStatementAst: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.level <span class="hljs-keyword">is</span> LEVEL_TOP
astType: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @isStatementAst o
<span class="hljs-string">&#x27;IfStatement&#x27;</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;ConditionalExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
isStatement = @isStatementAst o
<span class="hljs-keyword">return</span>
test: @condition.ast o, <span class="hljs-keyword">if</span> isStatement <span class="hljs-keyword">then</span> LEVEL_PAREN <span class="hljs-keyword">else</span> LEVEL_COND
consequent:
<span class="hljs-keyword">if</span> isStatement
@body.ast o, LEVEL_TOP
<span class="hljs-keyword">else</span>
@bodyNode().ast o, LEVEL_TOP
alternate:
<span class="hljs-keyword">if</span> @isChain
@elseBody.unwrap().ast o, <span class="hljs-keyword">if</span> isStatement <span class="hljs-keyword">then</span> LEVEL_TOP <span class="hljs-keyword">else</span> LEVEL_COND
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> isStatement <span class="hljs-keyword">and</span> @elseBody?.expressions?.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
@elseBody.expressions[<span class="hljs-number">0</span>].ast o, LEVEL_TOP
<span class="hljs-keyword">else</span>
@elseBody?.ast(o, LEVEL_TOP) ? <span class="hljs-literal">null</span>
postfix: !!@postfix
inverted: @type <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;unless&#x27;</span></pre></div></div>
</li>
<li id="section-350">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-350">&#x00a7;</a>
</div>
<p>A sequence expression e.g. <code>(a; b)</code>.
Currently only used during AST generation.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Sequence = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sequence</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
children: [<span class="hljs-string">&#x27;expressions&#x27;</span>]
constructor: <span class="hljs-function"><span class="hljs-params">(@expressions)</span> -&gt;</span>
super()
astNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> @expressions[<span class="hljs-number">0</span>].ast(o) <span class="hljs-keyword">if</span> @expressions.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
super o
astType: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;SequenceExpression&#x27;</span>
astProperties: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span>
expressions:
expression.ast(o) <span class="hljs-keyword">for</span> expression <span class="hljs-keyword">in</span> @expressions</pre></div></div>
</li>
<li id="section-351">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-351">&#x00a7;</a>
</div>
<h2 id="constants">Constants</h2>
</div>
</li>
<li id="section-352">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-352">&#x00a7;</a>
</div>
</div>
<div class="content"><div class='highlight'><pre>
UTILITIES =
modulo: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;function(a, b) { return (+a % (b = +b) + b) % b; }&#x27;</span>
boundMethodCheck: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&quot;
function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new Error(&#x27;Bound instance method accessed before binding&#x27;);
}
}
&quot;</span></pre></div></div>
</li>
<li id="section-353">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-353">&#x00a7;</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">&#x27;{}.hasOwnProperty&#x27;</span>
indexOf: <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;[].indexOf&#x27;</span>
slice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;[].slice&#x27;</span>
splice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">&#x27;[].splice&#x27;</span></pre></div></div>
</li>
<li id="section-354">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-354">&#x00a7;</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-355">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-355">&#x00a7;</a>
</div>
<p>Tabs are two spaces for pretty printing.</p>
</div>
<div class="content"><div class='highlight'><pre>TAB = <span class="hljs-string">&#x27; &#x27;</span>
SIMPLENUM = <span class="hljs-regexp">/^[+-]?\d+(?:_\d+)*$/</span>
SIMPLE_STRING_OMIT = <span class="hljs-regexp">/\s*\n\s*/g</span>
LEADING_BLANK_LINE = <span class="hljs-regexp">/^[^\n\S]*\n/</span>
TRAILING_BLANK_LINE = <span class="hljs-regexp">/\n[^\n\S]*$/</span>
STRING_OMIT = <span class="hljs-regexp">///
((?:\\\\)+) <span class="hljs-comment"># Consume (and preserve) an even number of backslashes.</span>
| \\[^\S\n]*\n\s* <span class="hljs-comment"># Remove escaped newlines.</span>
///</span>g
HEREGEX_OMIT = <span class="hljs-regexp">///
((?:\\\\)+) <span class="hljs-comment"># Consume (and preserve) an even number of backslashes.</span>
| \\(\s) <span class="hljs-comment"># Preserve escaped whitespace.</span>
| \s+(?:<span class="hljs-comment">#.*)? # Remove whitespace and comments.</span>
///</span>g</pre></div></div>
</li>
<li id="section-356">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-356">&#x00a7;</a>
</div>
<h2 id="helper-functions">Helper Functions</h2>
</div>
</li>
<li id="section-357">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-357">&#x00a7;</a>
</div>
</div>
</li>
<li id="section-358">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-358">&#x00a7;</a>
</div>
<p>Helper for ensuring that utility functions are assigned at the top level.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">utility</span> = <span class="hljs-params">(name, o)</span> -&gt;</span>
{root} = o.scope
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">of</span> root.utilities
root.utilities[name]
<span class="hljs-keyword">else</span>
ref = root.freeVariable name
root.assign ref, UTILITIES[name] o
root.utilities[name] = ref
<span class="hljs-function">
<span class="hljs-title">multident</span> = <span class="hljs-params">(code, tab, includingFirstLine = <span class="hljs-literal">yes</span>)</span> -&gt;</span>
endsWithNewLine = code[code.length - <span class="hljs-number">1</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;\n&#x27;</span>
code = (<span class="hljs-keyword">if</span> includingFirstLine <span class="hljs-keyword">then</span> tab <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>) + code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">&quot;$&amp;<span class="hljs-subst">#{tab}</span>&quot;</span>
code = code.replace <span class="hljs-regexp">/\s+$/</span>, <span class="hljs-string">&#x27;&#x27;</span>
code = code + <span class="hljs-string">&#x27;\n&#x27;</span> <span class="hljs-keyword">if</span> endsWithNewLine
code</pre></div></div>
</li>
<li id="section-359">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-359">&#x00a7;</a>
</div>
<p>Wherever in CoffeeScript 1 we mightve inserted a <code>makeCode &quot;#{@tab}&quot;</code> to
indent a line of code, now we must account for the possibility of comments
preceding that line of code. If there are such comments, indent each line of
such comments, and <em>then</em> indent the first following line of code.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">indentInitial</span> = <span class="hljs-params">(fragments, node)</span> -&gt;</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments
<span class="hljs-keyword">if</span> fragment.isHereComment
fragment.code = multident fragment.code, node.tab
<span class="hljs-keyword">else</span>
fragments.splice fragmentIndex, <span class="hljs-number">0</span>, node.makeCode <span class="hljs-string">&quot;<span class="hljs-subst">#{node.tab}</span>&quot;</span>
<span class="hljs-keyword">break</span>
fragments
<span class="hljs-function">
<span class="hljs-title">hasLineComments</span> = <span class="hljs-params">(node)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> node.comments
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> node.comments
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> comment.here <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span></pre></div></div>
</li>
<li id="section-360">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-360">&#x00a7;</a>
</div>
<p>Move the <code>comments</code> property from one object to another, deleting it from
the first object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">moveComments</span> = <span class="hljs-params">(<span class="hljs-keyword">from</span>, to)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> <span class="hljs-keyword">from</span>?.comments
attachCommentsToNode <span class="hljs-keyword">from</span>.comments, to
<span class="hljs-keyword">delete</span> <span class="hljs-keyword">from</span>.comments</pre></div></div>
</li>
<li id="section-361">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-361">&#x00a7;</a>
</div>
<p>Sometimes when compiling a node, we want to insert a fragment at the start
of an array of fragments; but if the start has one or more comment fragments,
we want to insert this fragment after those but before any non-comments.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">unshiftAfterComments</span> = <span class="hljs-params">(fragments, fragmentToInsert)</span> -&gt;</span>
inserted = <span class="hljs-literal">no</span>
<span class="hljs-keyword">for</span> fragment, fragmentIndex <span class="hljs-keyword">in</span> fragments <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> fragment.isComment
fragments.splice fragmentIndex, <span class="hljs-number">0</span>, fragmentToInsert
inserted = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">break</span>
fragments.push fragmentToInsert <span class="hljs-keyword">unless</span> inserted
fragments
<span class="hljs-function">
<span class="hljs-title">isLiteralArguments</span> = <span class="hljs-params">(node)</span> -&gt;</span>
node <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;arguments&#x27;</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-362">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-362">&#x00a7;</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>
<li id="section-363">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-363">&#x00a7;</a>
</div>
<p>Constructs a string or regex by escaping certain characters.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">makeDelimitedLiteral</span> = <span class="hljs-params">(body, {delimiter: delimiterOption, escapeNewlines, double, includeDelimiters = <span class="hljs-literal">yes</span>, escapeDelimiter = <span class="hljs-literal">yes</span>, convertTrailingNullEscapes} = {})</span> -&gt;</span>
body = <span class="hljs-string">&#x27;(?:)&#x27;</span> <span class="hljs-keyword">if</span> body <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">and</span> delimiterOption <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;/&#x27;</span>
escapeTemplateLiteralCurlies = delimiterOption <span class="hljs-keyword">is</span> <span class="hljs-string">&#x27;`&#x27;</span>
regex = <span class="hljs-regexp">///
(\\\\) <span class="hljs-comment"># Escaped backslash.</span>
| (\\0(?=\d)) <span class="hljs-comment"># Null character mistaken as octal escape.</span>
<span class="hljs-subst">#{
<span class="hljs-keyword">if</span> convertTrailingNullEscapes
<span class="hljs-regexp">/// | (\\0) $ ///</span>.source # Trailing <span class="hljs-literal">null</span> character that could be mistaken <span class="hljs-keyword">as</span> octal <span class="hljs-built_in">escape</span>.
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;&#x27;</span>
}</span>
<span class="hljs-subst">#{
<span class="hljs-keyword">if</span> escapeDelimiter
<span class="hljs-regexp">/// | \\?(<span class="hljs-subst">#{delimiterOption}</span>) ///</span>.source # (Possibly escaped) delimiter.
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;&#x27;</span>
}</span>
<span class="hljs-subst">#{
<span class="hljs-keyword">if</span> escapeTemplateLiteralCurlies
<span class="hljs-regexp">/// | \\?(\$\{) ///</span>.source # `<span class="language-javascript">${</span>` inside template literals must be escaped.
<span class="hljs-keyword">else</span>
<span class="hljs-string">&#x27;&#x27;</span>
}</span>
| \\?(?:
<span class="hljs-subst">#{<span class="hljs-keyword">if</span> escapeNewlines <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;(\n)|&#x27;</span> <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>}</span>
(\r)
| (\u2028)
| (\u2029)
) <span class="hljs-comment"># (Possibly escaped) newlines.</span>
| (\\.) <span class="hljs-comment"># Other escapes.</span>
///</span>g
body = body.replace regex, <span class="hljs-function"><span class="hljs-params">(match, backslash, nul, ...args)</span> -&gt;</span>
trailingNullEscape =
args.shift() <span class="hljs-keyword">if</span> convertTrailingNullEscapes
delimiter =
args.shift() <span class="hljs-keyword">if</span> escapeDelimiter
templateLiteralCurly =
args.shift() <span class="hljs-keyword">if</span> escapeTemplateLiteralCurlies
lf =
args.shift() <span class="hljs-keyword">if</span> escapeNewlines
[cr, ls, ps, other] = args
<span class="hljs-keyword">switch</span></pre></div></div>
</li>
<li id="section-364">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-364">&#x00a7;</a>
</div>
<p>Ignore escaped backslashes.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">when</span> backslash <span class="hljs-keyword">then</span> (<span class="hljs-keyword">if</span> double <span class="hljs-keyword">then</span> backslash + backslash <span class="hljs-keyword">else</span> backslash)
<span class="hljs-keyword">when</span> nul <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\\x00&#x27;</span>
<span class="hljs-keyword">when</span> trailingNullEscape <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;\\x00&quot;</span>
<span class="hljs-keyword">when</span> delimiter <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;\\<span class="hljs-subst">#{delimiter}</span>&quot;</span>
<span class="hljs-keyword">when</span> templateLiteralCurly <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;\\${&quot;</span>
<span class="hljs-keyword">when</span> lf <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\\n&#x27;</span>
<span class="hljs-keyword">when</span> cr <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\\r&#x27;</span>
<span class="hljs-keyword">when</span> ls <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\\u2028&#x27;</span>
<span class="hljs-keyword">when</span> ps <span class="hljs-keyword">then</span> <span class="hljs-string">&#x27;\\u2029&#x27;</span>
<span class="hljs-keyword">when</span> other <span class="hljs-keyword">then</span> (<span class="hljs-keyword">if</span> double <span class="hljs-keyword">then</span> <span class="hljs-string">&quot;\\<span class="hljs-subst">#{other}</span>&quot;</span> <span class="hljs-keyword">else</span> other)
printedDelimiter = <span class="hljs-keyword">if</span> includeDelimiters <span class="hljs-keyword">then</span> delimiterOption <span class="hljs-keyword">else</span> <span class="hljs-string">&#x27;&#x27;</span>
<span class="hljs-string">&quot;<span class="hljs-subst">#{printedDelimiter}</span><span class="hljs-subst">#{body}</span><span class="hljs-subst">#{printedDelimiter}</span>&quot;</span>
<span class="hljs-function">
<span class="hljs-title">sniffDirectives</span> = <span class="hljs-params">(expressions, {notFinalExpression} = {})</span> -&gt;</span>
index = <span class="hljs-number">0</span>
lastIndex = expressions.length - <span class="hljs-number">1</span>
<span class="hljs-keyword">while</span> index &lt;= lastIndex
<span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> index <span class="hljs-keyword">is</span> lastIndex <span class="hljs-keyword">and</span> notFinalExpression
expression = expressions[index]
<span class="hljs-keyword">if</span> (unwrapped = expression?.unwrap?()) <span class="hljs-keyword">instanceof</span> PassthroughLiteral <span class="hljs-keyword">and</span> unwrapped.generated
index++
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> expression <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expression.isString() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> expression.unwrap().shouldGenerateTemplateLiteral()
expressions[index] =
<span class="hljs-keyword">new</span> Directive expression
.withLocationDataFrom expression
index++
<span class="hljs-function">
<span class="hljs-title">astAsBlockIfNeeded</span> = <span class="hljs-params">(node, o)</span> -&gt;</span>
unwrapped = node.unwrap()
<span class="hljs-keyword">if</span> unwrapped <span class="hljs-keyword">instanceof</span> Block <span class="hljs-keyword">and</span> unwrapped.expressions.length &gt; <span class="hljs-number">1</span>
unwrapped.makeReturn <span class="hljs-literal">null</span>, <span class="hljs-literal">yes</span>
unwrapped.ast o, LEVEL_TOP
<span class="hljs-keyword">else</span>
node.ast o, LEVEL_PAREN</pre></div></div>
</li>
<li id="section-365">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-365">&#x00a7;</a>
</div>
<p>Helpers for <code>mergeLocationData</code> and <code>mergeAstLocationData</code> below.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">lesser</span> = <span class="hljs-params">(a, b)</span> -&gt;</span> <span class="hljs-keyword">if</span> a &lt; b <span class="hljs-keyword">then</span> a <span class="hljs-keyword">else</span> b
<span class="hljs-function"><span class="hljs-title">greater</span> = <span class="hljs-params">(a, b)</span> -&gt;</span> <span class="hljs-keyword">if</span> a &gt; b <span class="hljs-keyword">then</span> a <span class="hljs-keyword">else</span> b
<span class="hljs-function">
<span class="hljs-title">isAstLocGreater</span> = <span class="hljs-params">(a, b)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> a.line &gt; b.line
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> a.line <span class="hljs-keyword">is</span> b.line
a.column &gt; b.column
<span class="hljs-function">
<span class="hljs-title">isLocationDataStartGreater</span> = <span class="hljs-params">(a, b)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> a.first_line &gt; b.first_line
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> a.first_line <span class="hljs-keyword">is</span> b.first_line
a.first_column &gt; b.first_column
<span class="hljs-function">
<span class="hljs-title">isLocationDataEndGreater</span> = <span class="hljs-params">(a, b)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> a.last_line &gt; b.last_line
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> a.last_line <span class="hljs-keyword">is</span> b.last_line
a.last_column &gt; b.last_column</pre></div></div>
</li>
<li id="section-366">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-366">&#x00a7;</a>
</div>
<p>Take two nodes location data and return a new <code>locationData</code> object that
encompasses the location data of both nodes. So the new <code>first_line</code> value
will be the earlier of the two nodes <code>first_line</code> values, the new
<code>last_column</code> the later of the two nodes <code>last_column</code> values, etc.</p>
<p>If you only want to extend the first nodes location data with the start or
end location data of the second node, pass the <code>justLeading</code> or <code>justEnding</code>
options. So e.g. if <code>first</code>s range is [4, 5] and <code>second</code>s range is [1, 10],
youd get:</p>
<pre><code>mergeLocationData(first, second).range <span class="hljs-comment"># [1, 10]</span>
mergeLocationData(first, second, justLeading: <span class="hljs-literal">yes</span>).range <span class="hljs-comment"># [1, 5]</span>
mergeLocationData(first, second, justEnding: <span class="hljs-literal">yes</span>).range <span class="hljs-comment"># [4, 10]</span>
</code></pre>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.mergeLocationData = mergeLocationData = <span class="hljs-function"><span class="hljs-params">(locationDataA, locationDataB, {justLeading, justEnding} = {})</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.assign(
<span class="hljs-keyword">if</span> justEnding
first_line: locationDataA.first_line
first_column: locationDataA.first_column
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> isLocationDataStartGreater locationDataA, locationDataB
first_line: locationDataB.first_line
first_column: locationDataB.first_column
<span class="hljs-keyword">else</span>
first_line: locationDataA.first_line
first_column: locationDataA.first_column
,
<span class="hljs-keyword">if</span> justLeading
last_line: locationDataA.last_line
last_column: locationDataA.last_column
last_line_exclusive: locationDataA.last_line_exclusive
last_column_exclusive: locationDataA.last_column_exclusive
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> isLocationDataEndGreater locationDataA, locationDataB
last_line: locationDataA.last_line
last_column: locationDataA.last_column
last_line_exclusive: locationDataA.last_line_exclusive
last_column_exclusive: locationDataA.last_column_exclusive
<span class="hljs-keyword">else</span>
last_line: locationDataB.last_line
last_column: locationDataB.last_column
last_line_exclusive: locationDataB.last_line_exclusive
last_column_exclusive: locationDataB.last_column_exclusive
,
range: [
<span class="hljs-keyword">if</span> justEnding
locationDataA.range[<span class="hljs-number">0</span>]
<span class="hljs-keyword">else</span>
lesser locationDataA.range[<span class="hljs-number">0</span>], locationDataB.range[<span class="hljs-number">0</span>]
,
<span class="hljs-keyword">if</span> justLeading
locationDataA.range[<span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>
greater locationDataA.range[<span class="hljs-number">1</span>], locationDataB.range[<span class="hljs-number">1</span>]
]
)</pre></div></div>
</li>
<li id="section-367">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-367">&#x00a7;</a>
</div>
<p>Take two AST nodes, or two AST nodes location data objects, and return a new
location data object that encompasses the location data of both nodes. So the
new <code>start</code> value will be the earlier of the two nodes <code>start</code> values, the
new <code>end</code> value will be the later of the two nodes <code>end</code> values, etc.</p>
<p>If you only want to extend the first nodes location data with the start or
end location data of the second node, pass the <code>justLeading</code> or <code>justEnding</code>
options. So e.g. if <code>first</code>s range is [4, 5] and <code>second</code>s range is [1, 10],
youd get:</p>
<pre><code>mergeAstLocationData(first, second).range <span class="hljs-comment"># [1, 10]</span>
mergeAstLocationData(first, second, justLeading: <span class="hljs-literal">yes</span>).range <span class="hljs-comment"># [1, 5]</span>
mergeAstLocationData(first, second, justEnding: <span class="hljs-literal">yes</span>).range <span class="hljs-comment"># [4, 10]</span>
</code></pre>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.mergeAstLocationData = mergeAstLocationData = <span class="hljs-function"><span class="hljs-params">(nodeA, nodeB, {justLeading, justEnding} = {})</span> -&gt;</span>
<span class="hljs-keyword">return</span>
loc:
start:
<span class="hljs-keyword">if</span> justEnding
nodeA.loc.start
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> isAstLocGreater nodeA.loc.start, nodeB.loc.start
nodeB.loc.start
<span class="hljs-keyword">else</span>
nodeA.loc.start
end:
<span class="hljs-keyword">if</span> justLeading
nodeA.loc.end
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> isAstLocGreater nodeA.loc.end, nodeB.loc.end
nodeA.loc.end
<span class="hljs-keyword">else</span>
nodeB.loc.end
range: [
<span class="hljs-keyword">if</span> justEnding
nodeA.range[<span class="hljs-number">0</span>]
<span class="hljs-keyword">else</span>
lesser nodeA.range[<span class="hljs-number">0</span>], nodeB.range[<span class="hljs-number">0</span>]
,
<span class="hljs-keyword">if</span> justLeading
nodeA.range[<span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>
greater nodeA.range[<span class="hljs-number">1</span>], nodeB.range[<span class="hljs-number">1</span>]
]
start:
<span class="hljs-keyword">if</span> justEnding
nodeA.start
<span class="hljs-keyword">else</span>
lesser nodeA.start, nodeB.start
end:
<span class="hljs-keyword">if</span> justLeading
nodeA.end
<span class="hljs-keyword">else</span>
greater nodeA.end, nodeB.end</pre></div></div>
</li>
<li id="section-368">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-368">&#x00a7;</a>
</div>
<p>Convert Jison-style node class location data to Babel-style location data</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.jisonLocationDataToAstLocationData = jisonLocationDataToAstLocationData = <span class="hljs-function"><span class="hljs-params">({first_line, first_column, last_line_exclusive, last_column_exclusive, range})</span> -&gt;</span>
<span class="hljs-keyword">return</span>
loc:
start:
line: first_line + <span class="hljs-number">1</span>
column: first_column
end:
line: last_line_exclusive + <span class="hljs-number">1</span>
column: last_column_exclusive
range: [
range[<span class="hljs-number">0</span>]
range[<span class="hljs-number">1</span>]
]
start: range[<span class="hljs-number">0</span>]
end: range[<span class="hljs-number">1</span>]</pre></div></div>
</li>
<li id="section-369">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-369">&#x00a7;</a>
</div>
<p>Generate a zero-width location data that corresponds to the end of another nodes location.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">zeroWidthLocationDataFromEndLocation</span> = <span class="hljs-params">({range: [, endRange], last_line_exclusive, last_column_exclusive})</span> -&gt;</span> {
first_line: last_line_exclusive
first_column: last_column_exclusive
last_line: last_line_exclusive
last_column: last_column_exclusive
last_line_exclusive
last_column_exclusive
range: [endRange, endRange]
}
<span class="hljs-function">
<span class="hljs-title">extractSameLineLocationDataFirst</span> = <span class="hljs-params">(numChars)</span> -&gt;</span> ({range: [startRange], first_line, first_column}) -&gt; {
first_line
first_column
last_line: first_line
last_column: first_column + numChars - <span class="hljs-number">1</span>
last_line_exclusive: first_line
last_column_exclusive: first_column + numChars
range: [startRange, startRange + numChars]
}
<span class="hljs-function">
<span class="hljs-title">extractSameLineLocationDataLast</span> = <span class="hljs-params">(numChars)</span> -&gt;</span> ({range: [, endRange], last_line, last_column, last_line_exclusive, last_column_exclusive}) -&gt; {
first_line: last_line
first_column: last_column - (numChars - <span class="hljs-number">1</span>)
last_line: last_line
last_column: last_column
last_line_exclusive
last_column_exclusive
range: [endRange - numChars, endRange]
}</pre></div></div>
</li>
<li id="section-370">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-370">&#x00a7;</a>
</div>
<p>We dont currently have a token corresponding to the empty space
between interpolation/JSX expression braces, so piece together the location
data by trimming the braces from the Interpolations location data.
Technically the last_line/last_column calculation here could be
incorrect if the ending brace is preceded by a newline, but
last_line/last_column arent used for AST generation anyway.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">emptyExpressionLocationData</span> = <span class="hljs-params">({interpolationNode: element, openingBrace, closingBrace})</span> -&gt;</span>
first_line: element.locationData.first_line
first_column: element.locationData.first_column + openingBrace.length
last_line: element.locationData.last_line
last_column: element.locationData.last_column - closingBrace.length
last_line_exclusive: element.locationData.last_line
last_column_exclusive: element.locationData.last_column
range: [
element.locationData.range[<span class="hljs-number">0</span>] + openingBrace.length
element.locationData.range[<span class="hljs-number">1</span>] - closingBrace.length
]</pre></div></div>
</li>
</ul>
</div>
</body>
</html>