jashkenas--coffeescript/documentation/docs/nodes.html

5011 lines
276 KiB
HTML
Raw Normal View History

<!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">
2014-08-26 12:24:29 -04:00
<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="coffee-script.html">
coffee-script.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>
2013-03-18 01:06:33 -04:00
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>nodes.coffee</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
<a class="pilcrow" href="#section-1">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-01-29 23:54:00 -05:00
the syntax tree into a string of JavaScript code, call <code>compile()</code> on the root.</p>
</div>
2014-08-23 10:08:39 -04:00
<div class="content"><div class='highlight'><pre>
Error.stackTraceLimit = Infinity
2013-03-04 14:19:08 -05:00
2014-01-29 23:54:00 -05:00
{Scope} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./scope'</span>
2016-09-22 16:19:43 -04:00
{isUnassignable, JS_FORBIDDEN} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./lexer'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
<li id="section-2">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">&#182;</a>
</div>
2014-01-29 23:54:00 -05:00
<p>Import the helpers we plan to use.</p>
</div>
2015-02-18 15:43:33 -05:00
<div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, some,
2014-01-29 23:54:00 -05:00
addLocationDataFn, locationDataToString, throwSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
<li id="section-3">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">&#182;</a>
</div>
2014-01-29 23:54:00 -05:00
<p>Functions required by parser</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.extend = extend
exports.addLocationDataFn = addLocationDataFn</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
<li id="section-4">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
<a class="pilcrow" href="#section-4">&#182;</a>
</div>
2014-08-23 10:08:39 -04:00
<p>Constant functions for nodes that dont need customization.</p>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">YES</span> = -&gt;</span> <span class="hljs-literal">yes</span>
<span class="hljs-function"><span class="hljs-title">NO</span> = -&gt;</span> <span class="hljs-literal">no</span>
<span class="hljs-function"><span class="hljs-title">THIS</span> = -&gt;</span> <span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-function"><span class="hljs-title">NEGATE</span> = -&gt;</span> @negated = <span class="hljs-keyword">not</span> @negated; <span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
<li id="section-5">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-01-29 23:54:00 -05:00
<a class="pilcrow" href="#section-5">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="codefragment">CodeFragment</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">&#182;</a>
</div>
<p>The various nodes defined below all compile to a collection of <strong>CodeFragment</strong> objects.
2013-03-04 14:19:08 -05:00
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
2014-08-23 10:08:39 -04:00
all the CodeFragments <code>code</code> snippets, in order.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.CodeFragment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CodeFragment</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(parent, code)</span> -&gt;</span>
@code = <span class="hljs-string">"<span class="hljs-subst">#{code}</span>"</span>
@locationData = parent?.locationData
@type = parent?.constructor?.name <span class="hljs-keyword">or</span> <span class="hljs-string">'unknown'</span>
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
toString: <span class="hljs-function">-&gt;</span>
<span class="hljs-string">"<span class="hljs-subst">#{@code}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> @locationData <span class="hljs-keyword">then</span> <span class="hljs-string">": "</span> + locationDataToString(@locationData) <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-7">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-7">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Convert an array of CodeFragments into a string.</p>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">fragmentsToText</span> = <span class="hljs-params">(fragments)</span> -&gt;</span>
(fragment.code <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments).join(<span class="hljs-string">''</span>)</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-8">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-8">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="base">Base</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<p>The <strong>Base</strong> is the abstract base class for all nodes in the syntax tree.
Each subclass implements the <code>compileNode</code> method, which performs the
code generation for that node. To compile a node to JavaScript,
call <code>compile</code> on it, which wraps <code>compileNode</code> in some generic extra smarts,
to know when the generated code needs to be wrapped up in a closure.
An options hash is passed and cloned throughout, containing information about
the environment from higher in the tree (such as if a returned value is
being requested by the surrounding function), information about the current
2014-01-29 23:54:00 -05:00
scope, and indentation level.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Base = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Base</span></span>
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
compile: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
fragmentsToText @compileToFragments o, lvl</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-10">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-10">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-08-23 10:08:39 -04:00
<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
2014-01-29 23:54:00 -05:00
return results).</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
o = extend {}, o
2014-01-29 23:54:00 -05:00
o.level = lvl <span class="hljs-keyword">if</span> lvl
2016-09-22 16:19:43 -04:00
node = @unfoldSoak(o) <span class="hljs-keyword">or</span> <span class="hljs-keyword">this</span>
2013-03-18 01:06:33 -04:00
node.tab = o.indent
2014-01-29 23:54:00 -05:00
<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)
2013-03-18 01:06:33 -04:00
node.compileNode o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
node.compileClosure o</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-11">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-11">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Statements converted into expressions via closure-wrapping share a scope
2014-01-29 23:54:00 -05:00
object with their parent closure, to preserve the expected lexical scope.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileClosure: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> jumpNode = @jumps()
2014-01-29 23:54:00 -05:00
jumpNode.error <span class="hljs-string">'cannot use a pure statement in an expression'</span>
o.sharedScope = <span class="hljs-literal">yes</span>
func = <span class="hljs-keyword">new</span> Code [], Block.wrap [<span class="hljs-keyword">this</span>]
args = []
2016-09-22 16:19:43 -04:00
<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]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> argumentsNode
meth = <span class="hljs-string">'apply'</span>
2016-09-22 16:19:43 -04:00
args.push <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
meth = <span class="hljs-string">'call'</span>
2016-09-22 16:19:43 -04:00
func = <span class="hljs-keyword">new</span> Value func, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName meth]
2015-01-29 12:20:46 -05:00
parts = (<span class="hljs-keyword">new</span> Call func, args).compileNode o
2015-04-15 11:26:30 -04:00
<span class="hljs-keyword">if</span> func.isGenerator <span class="hljs-keyword">or</span> func.base?.isGenerator
2016-09-22 16:19:43 -04:00
parts.unshift @makeCode <span class="hljs-string">"(yield* "</span>
parts.push @makeCode <span class="hljs-string">")"</span>
2015-01-29 12:20:46 -05:00
parts</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-12">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-12">&#182;</a>
2013-03-18 01:06:33 -04:00
</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,
2014-01-29 23:54:00 -05:00
by assigning it to a temporary variable. Pass a level to precompile.</p>
2013-03-04 14:19:08 -05:00
<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
2014-01-29 23:54:00 -05:00
the two values are raw nodes which have not been compiled.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> cache: <span class="hljs-function"><span class="hljs-params">(o, level, isComplex)</span> -&gt;</span>
complex = <span class="hljs-keyword">if</span> isComplex? <span class="hljs-keyword">then</span> isComplex <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> @isComplex()
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> complex
2016-09-22 16:19:43 -04:00
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
2014-01-29 23:54:00 -05:00
sub = <span class="hljs-keyword">new</span> Assign ref, <span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
<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]
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
ref = <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> @compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span>
2015-02-18 15:43:33 -05:00
[ref, ref]
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
cacheToCodeFragments: <span class="hljs-function"><span class="hljs-params">(cacheValues)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
[fragmentsToText(cacheValues[<span class="hljs-number">0</span>]), fragmentsToText(cacheValues[<span class="hljs-number">1</span>])]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-13">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-13">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Construct a node that returns the current nodes result.
2010-03-23 00:18:50 -04:00
Note that this is overridden for smarter behavior for
2014-08-23 10:08:39 -04:00
many statement nodes (e.g. If, For)…</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
me = @unwrapAll()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> res
<span class="hljs-keyword">new</span> Call <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">"<span class="hljs-subst">#{res}</span>.push"</span>), [me]
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Return me</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-14">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-14">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-01-29 23:54:00 -05:00
scope boundaries.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> contains: <span class="hljs-function"><span class="hljs-params">(pred)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
node = <span class="hljs-literal">undefined</span>
2016-09-22 16:19:43 -04:00
@traverseChildren <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(n)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> pred n
2013-03-18 01:06:33 -04:00
node = n
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span>
2013-03-18 01:06:33 -04:00
node</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-15">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-15">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Pull out the last non-comment node of a node list.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> lastNonComment: <span class="hljs-function"><span class="hljs-params">(list)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
i = list.length
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> list[i] <span class="hljs-keyword">while</span> i-- <span class="hljs-keyword">when</span> list[i] <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
<span class="hljs-literal">null</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-16">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-16">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p><code>toString</code> representation of the node, for inspecting the parse tree.
2014-01-29 23:54:00 -05:00
This is what <code>coffee --nodes</code> prints out.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> toString: <span class="hljs-function"><span class="hljs-params">(idt = <span class="hljs-string">''</span>, name = @constructor.name)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
tree = <span class="hljs-string">'\n'</span> + idt + name
2016-09-22 16:19:43 -04:00
tree += <span class="hljs-string">'?'</span> <span class="hljs-keyword">if</span> @soak
@eachChild (node) -&gt; tree += node.toString idt + TAB
2013-03-18 01:06:33 -04:00
tree</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-17">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-17">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Passes each child to a function, breaking when the function returns <code>false</code>.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> eachChild: <span class="hljs-function"><span class="hljs-params">(func)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">unless</span> @children
<span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> @children <span class="hljs-keyword">when</span> @[attr]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> flatten [@[attr]]
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> func(child) <span class="hljs-keyword">is</span> <span class="hljs-literal">false</span>
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
traverseChildren: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -&gt;</span>
@eachChild (child) -&gt;
2013-06-02 01:37:45 -04:00
recur = func(child)
2014-01-29 23:54:00 -05:00
child.traverseChildren(crossScope, func) <span class="hljs-keyword">unless</span> recur <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span>
2016-09-22 16:19:43 -04:00
invert: <span class="hljs-function">-&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
unwrapAll: <span class="hljs-function">-&gt;</span>
2014-01-29 23:54:00 -05:00
node = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">until</span> node <span class="hljs-keyword">is</span> node = node.unwrap()
2013-03-18 01:06:33 -04:00
node</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-18">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-18">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Default implementations of the common node properties and methods. Nodes
2014-01-29 23:54:00 -05:00
will override these with custom logic, if needed.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> children: []
2013-03-18 01:06:33 -04:00
isStatement : NO
jumps : NO
isComplex : YES
isChainable : NO
isAssignable : NO
2016-09-22 16:19:43 -04:00
isNumber : NO
2013-03-18 01:06:33 -04:00
unwrap : THIS
unfoldSoak : NO</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-19">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-19">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Is this node used to assign a certain variable?</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> assigns: NO</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-20">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-20">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>For this node and all descendents, set the location data to <code>locationData</code>
2014-01-29 23:54:00 -05:00
if the location data is not already set.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> updateLocationDataIfMissing: <span class="hljs-function"><span class="hljs-params">(locationData)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @locationData
@locationData = locationData
2013-02-25 03:12:22 -05:00
2016-09-22 16:19:43 -04:00
@eachChild (child) -&gt;
2013-03-18 01:06:33 -04:00
child.updateLocationDataIfMissing locationData</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-21">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-21">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Throw a SyntaxError associated with this nodes location.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> error: <span class="hljs-function"><span class="hljs-params">(message)</span> -&gt;</span>
throwSyntaxError message, @locationData
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
makeCode: <span class="hljs-function"><span class="hljs-params">(code)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">new</span> CodeFragment <span class="hljs-keyword">this</span>, code
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
wrapInBraces: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -&gt;</span>
[].concat @makeCode(<span class="hljs-string">'('</span>), fragments, @makeCode(<span class="hljs-string">')'</span>)</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-22">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-22">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p><code>fragmentsList</code> is an array of arrays of fragments. Each array in fragmentsList will be
2013-03-04 14:19:08 -05:00
concatonated together, with <code>joinStr</code> added in between each, to produce a final flat array
2014-01-29 23:54:00 -05:00
of fragments.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> joinFragmentArrays: <span class="hljs-function"><span class="hljs-params">(fragmentsList, joinStr)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
answer = []
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> fragments,i <span class="hljs-keyword">in</span> fragmentsList
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push @makeCode joinStr
2013-03-18 01:06:33 -04:00
answer = answer.concat fragments
answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-23">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-23">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="block">Block</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>The block is the list of expressions that forms the body of an
2016-09-22 16:19:43 -04:00
indented block of code the implementation of a function, a clause in an
2014-08-23 10:08:39 -04:00
<code>if</code>, <code>switch</code>, or <code>try</code>, and so on…</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Block = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Block</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -&gt;</span>
@expressions = compact flatten nodes <span class="hljs-keyword">or</span> []
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'expressions'</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-25">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-25">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Tack an expression on to the end of this expression list.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> push: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
@expressions.push node
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-26">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-26">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Remove and return the last expression of this expression list.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> pop: <span class="hljs-function">-&gt;</span>
@expressions.pop()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-27">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-27">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Add an expression at the beginning of this expression list.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> unshift: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
@expressions.unshift node
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-28">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-28">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>If this Block consists of just a single node, unwrap it by pulling
2014-01-29 23:54:00 -05:00
it back out.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> unwrap: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @expressions.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> @expressions[<span class="hljs-number">0</span>] <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-29">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-29">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Is this an empty block of code?</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> isEmpty: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @expressions.length
2016-09-22 16:19:43 -04:00
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
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
<span class="hljs-literal">no</span>
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
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
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = exp.jumps o</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-30">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-30">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>A Block node does not return its entire body, rather it
2014-01-29 23:54:00 -05:00
ensures that the final expression is returned.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
len = @expressions.length
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">while</span> len--
2016-09-22 16:19:43 -04:00
expr = @expressions[len]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
2016-09-22 16:19:43 -04:00
@expressions[len] = expr.makeReturn res
@expressions.splice(len, <span class="hljs-number">1</span>) <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> expr.expression
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-31">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-31">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>A <strong>Block</strong> is the only node that can serve as the root.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o = {}, level)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.scope <span class="hljs-keyword">then</span> <span class="hljs-keyword">super</span> o, level <span class="hljs-keyword">else</span> @compileRoot o</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-32">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-32">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Compile all expressions within the <strong>Block</strong> body. If we need to
2014-08-23 10:08:39 -04:00
return the result, and its an expression, simply return it. If its a
2014-01-29 23:54:00 -05:00
statement, ask the statement to do so.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@tab = o.indent
2014-01-29 23:54:00 -05:00
top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP
2013-03-18 01:06:33 -04:00
compiledNodes = []
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> node, index <span class="hljs-keyword">in</span> @expressions
2013-03-04 14:19:08 -05:00
2013-03-18 01:06:33 -04:00
node = node.unwrapAll()
2014-01-29 23:54:00 -05:00
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>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-33">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-33">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>This is a nested block. We dont do anything special here like enclose
2011-08-04 23:17:23 -04:00
it in a new scope; we just compile the statements in this block along with
2014-01-29 23:54:00 -05:00
our own</p>
</div>
2013-03-18 01:06:33 -04:00
<div class="content"><div class='highlight'><pre> compiledNodes.push node.compileNode o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> top
node.front = <span class="hljs-literal">true</span>
2013-03-18 01:06:33 -04:00
fragments = node.compileToFragments o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">unless</span> node.isStatement o
2016-09-22 16:19:43 -04:00
fragments.unshift @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>"</span>
fragments.push @makeCode <span class="hljs-string">";"</span>
2013-03-18 01:06:33 -04:00
compiledNodes.push fragments
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
compiledNodes.push node.compileToFragments o, LEVEL_LIST
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> top
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @spaced
<span class="hljs-keyword">return</span> [].concat @joinFragmentArrays(compiledNodes, <span class="hljs-string">'\n\n'</span>), @makeCode(<span class="hljs-string">"\n"</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> @joinFragmentArrays(compiledNodes, <span class="hljs-string">'\n'</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> compiledNodes.length
2016-09-22 16:19:43 -04:00
answer = @joinFragmentArrays(compiledNodes, <span class="hljs-string">', '</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
answer = [@makeCode <span class="hljs-string">"void 0"</span>]
<span class="hljs-keyword">if</span> compiledNodes.length &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> o.level &gt;= LEVEL_LIST <span class="hljs-keyword">then</span> @wrapInBraces answer <span class="hljs-keyword">else</span> answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-34">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-34">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>If we happen to be the top-level <strong>Block</strong>, wrap everything in
a safety closure, unless requested not to.
It would be better not to generate them in the first place, but for now,
2014-01-29 23:54:00 -05:00
clean up obvious double-parentheses.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileRoot: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
o.indent = <span class="hljs-keyword">if</span> o.bare <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> TAB
2013-03-18 01:06:33 -04:00
o.level = LEVEL_TOP
2016-09-22 16:19:43 -04:00
@spaced = <span class="hljs-literal">yes</span>
2015-01-29 12:20:46 -05:00
o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-literal">null</span>, o.referencedVars ? []</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-35">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-35">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Mark given local variables in the root scope as parameters so they dont
2014-01-29 23:54:00 -05:00
end up being declared on this block.</p>
</div>
2014-01-29 23:54:00 -05:00
<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> []
2013-03-18 01:06:33 -04:00
prelude = []
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">unless</span> o.bare
2016-09-22 16:19:43 -04:00
preludeExps = <span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> @expressions
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp.unwrap() <span class="hljs-keyword">instanceof</span> Comment
2013-03-18 01:06:33 -04:00
exp
2016-09-22 16:19:43 -04:00
rest = @expressions[preludeExps.length...]
@expressions = preludeExps
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> preludeExps.length
2016-09-22 16:19:43 -04:00
prelude = @compileNode merge(o, indent: <span class="hljs-string">''</span>)
prelude.push @makeCode <span class="hljs-string">"\n"</span>
@expressions = rest
fragments = @compileWithDeclarations o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> o.bare
2016-09-22 16:19:43 -04:00
[].concat prelude, @makeCode(<span class="hljs-string">"(function() {\n"</span>), fragments, @makeCode(<span class="hljs-string">"\n}).call(this);\n"</span>)</pre></div></div>
2013-03-18 01:06:33 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-36">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-36">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Compile the expressions body for the contents of a function, with
2014-01-29 23:54:00 -05:00
declarations of all inner variables pushed up to the top.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileWithDeclarations: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
fragments = []
post = []
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> @expressions
2013-03-18 01:06:33 -04:00
exp = exp.unwrap()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-keyword">or</span> exp <span class="hljs-keyword">instanceof</span> Literal
2016-09-22 16:19:43 -04:00
o = merge(o, level: LEVEL_TOP)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> i
2016-09-22 16:19:43 -04:00
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
2013-03-18 01:06:33 -04:00
{scope} = o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> scope.expressions <span class="hljs-keyword">is</span> <span class="hljs-keyword">this</span>
2013-03-18 01:06:33 -04:00
declars = o.scope.hasDeclarations()
assigns = scope.hasAssignments
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> declars <span class="hljs-keyword">or</span> assigns
2016-09-22 16:19:43 -04:00
fragments.push @makeCode <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> i
fragments.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>var "</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> declars
2016-09-22 16:19:43 -04:00
fragments.push @makeCode scope.declaredVariables().join(<span class="hljs-string">', '</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> assigns
2016-09-22 16:19:43 -04:00
fragments.push @makeCode <span class="hljs-string">",\n<span class="hljs-subst">#{@tab + TAB}</span>"</span> <span class="hljs-keyword">if</span> declars
fragments.push @makeCode scope.assignedVariables().join(<span class="hljs-string">",\n<span class="hljs-subst">#{@tab + TAB}</span>"</span>)
fragments.push @makeCode <span class="hljs-string">";\n<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @spaced <span class="hljs-keyword">then</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">and</span> post.length
2016-09-22 16:19:43 -04:00
fragments.push @makeCode <span class="hljs-string">"\n"</span>
2013-03-18 01:06:33 -04:00
fragments.concat post</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-37">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-37">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Wrap up the given nodes as a <strong>Block</strong>, unless it already happens
2014-01-29 23:54:00 -05:00
to be one.</p>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> @wrap: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> nodes.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Block
<span class="hljs-keyword">new</span> Block nodes</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-38">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-38">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="literal">Literal</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
<li id="section-39">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-39">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<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,
2014-08-23 10:08:39 -04:00
<code>true</code>, <code>false</code>, <code>null</code></p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Literal = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Literal</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@value)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
isComplex: NO
2016-09-22 16:19:43 -04:00
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
name <span class="hljs-keyword">is</span> @value
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode @value]
2016-09-22 16:19:43 -04:00
toString: <span class="hljs-function">-&gt;</span>
<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @isStatement() <span class="hljs-keyword">then</span> <span class="hljs-keyword">super</span> <span class="hljs-keyword">else</span> @constructor.name}</span>: <span class="hljs-subst">#{@value}</span>"</span>
2016-09-22 16:19:43 -04:00
exports.NumberLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NumberLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
exports.InfinityLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InfinityLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NumberLiteral</span></span>
compileNode: <span class="hljs-function">-&gt;</span>
[@makeCode <span class="hljs-string">'2e308'</span>]
2016-09-22 16:19:43 -04:00
exports.NaNLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NaNLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NumberLiteral</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'NaN'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = [@makeCode <span class="hljs-string">'0/0'</span>]
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_OP <span class="hljs-keyword">then</span> @wrapInBraces code <span class="hljs-keyword">else</span> code
exports.StringLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.RegexLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegexLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.PassthroughLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PassthroughLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
exports.IdentifierLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IdentifierLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isAssignable: YES
exports.PropertyName = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PropertyName</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isAssignable: YES
exports.StatementLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StatementLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
isStatement: YES
makeReturn: THIS
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">'break'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (o?.<span class="hljs-keyword">loop</span> <span class="hljs-keyword">or</span> o?.block)
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> @value <span class="hljs-keyword">is</span> <span class="hljs-string">'continue'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o?.<span class="hljs-keyword">loop</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{@value}</span>;"</span>]
exports.ThisLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThisLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'this'</span>
2012-05-14 14:45:20 -04:00
2016-09-22 16:19:43 -04:00
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]
2012-05-14 14:45:20 -04:00
2016-09-22 16:19:43 -04:00
exports.UndefinedLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UndefinedLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'undefined'</span>
2012-05-14 14:45:20 -04:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@makeCode <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_ACCESS <span class="hljs-keyword">then</span> <span class="hljs-string">'(void 0)'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'void 0'</span>]
2013-06-02 01:37:45 -04:00
2016-09-22 16:19:43 -04:00
exports.NullLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NullLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span>
constructor: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-string">'null'</span>
exports.BooleanLiteral = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BooleanLiteral</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Literal</span></span></pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-40">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-40">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="return">Return</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
<li id="section-41">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-41">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<p>A <code>return</code> is a <em>pureStatement</em> wrapping it in a closure wouldnt
2014-01-29 23:54:00 -05:00
make sense.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Return = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Return</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'expression'</span>]
2016-09-22 16:19:43 -04:00
isStatement: YES
makeReturn: THIS
jumps: THIS
2016-09-22 16:19:43 -04:00
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
expr = @expression?.makeReturn()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">and</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">then</span> expr.compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span> o, level
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
answer = []</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-42">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-42">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>TODO: If we call expression.compile() here twice, well sometimes get back different results!</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> answer.push @makeCode @tab + <span class="hljs-string">"return<span class="hljs-subst">#{<span class="hljs-keyword">if</span> @expression <span class="hljs-keyword">then</span> <span class="hljs-string">" "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>}</span>"</span>
<span class="hljs-keyword">if</span> @expression
answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
answer.push @makeCode <span class="hljs-string">";"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> answer</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-43">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-43">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p><code>yield return</code> works exactly like <code>return</code>, except that it turns the function
into a generator.</p>
2014-08-23 10:08:39 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.YieldReturn = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">YieldReturn</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Return</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">'yield can only occur inside functions'</span>
<span class="hljs-keyword">super</span></pre></div></div>
2014-08-23 10:08:39 -04:00
</li>
<li id="section-44">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-44">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<h3 id="value">Value</h3>
</div>
</li>
<li id="section-45">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-45">&#182;</a>
</div>
2014-08-23 10:08:39 -04:00
<p>A value, variable or literal or parenthesized, indexed or dotted into,
2014-01-29 23:54:00 -05:00
or vanilla.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Value = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Value</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(base, props, tag)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<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
2016-09-22 16:19:43 -04:00
@base = base
@properties = props <span class="hljs-keyword">or</span> []
2014-01-29 23:54:00 -05:00
@[tag] = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> tag
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'base'</span>, <span class="hljs-string">'properties'</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-46">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-46">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Add a property (or <em>properties</em> ) <code>Access</code> to the list.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> add: <span class="hljs-function"><span class="hljs-params">(props)</span> -&gt;</span>
@properties = @properties.concat props
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
hasProperties: <span class="hljs-function">-&gt;</span>
!!@properties.length
2016-09-22 16:19:43 -04:00
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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-47">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-47">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Some boolean checks for the benefit of other nodes.</p>
</div>
2016-09-22 16:19:43 -04:00
<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)
isComplex : <span class="hljs-function">-&gt;</span> @hasProperties() <span class="hljs-keyword">or</span> @base.isComplex()
isAssignable : <span class="hljs-function">-&gt;</span> @hasProperties() <span class="hljs-keyword">or</span> @base.isAssignable()
isNumber : <span class="hljs-function">-&gt;</span> @bareLiteral(NumberLiteral)
isString : <span class="hljs-function">-&gt;</span> @bareLiteral(StringLiteral)
isRegex : <span class="hljs-function">-&gt;</span> @bareLiteral(RegexLiteral)
isUndefined : <span class="hljs-function">-&gt;</span> @bareLiteral(UndefinedLiteral)
isNull : <span class="hljs-function">-&gt;</span> @bareLiteral(NullLiteral)
isBoolean : <span class="hljs-function">-&gt;</span> @bareLiteral(BooleanLiteral)
isAtomic : <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> @properties.concat @base
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> node.soak <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> Call
<span class="hljs-literal">yes</span>
2016-09-22 16:19:43 -04:00
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()
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
isStatement : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.isStatement o
assigns : <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.assigns name
jumps : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-keyword">not</span> @properties.length <span class="hljs-keyword">and</span> @base.jumps o
2016-09-22 16:19:43 -04:00
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)
2016-09-22 16:19:43 -04:00
isSplice: <span class="hljs-function">-&gt;</span>
[..., lastProp] = @properties
2015-02-18 15:43:33 -05:00
lastProp <span class="hljs-keyword">instanceof</span> Slice
2010-03-23 00:18:50 -04:00
2016-09-22 16:19:43 -04:00
looksStatic: <span class="hljs-function"><span class="hljs-params">(className)</span> -&gt;</span>
@base.value <span class="hljs-keyword">is</span> className <span class="hljs-keyword">and</span> @properties.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span>
@properties[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'prototype'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-48">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-48">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>The value can be unwrapped as its inner node, if there are no attached
2014-01-29 23:54:00 -05:00
properties.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> unwrap: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @properties.length <span class="hljs-keyword">then</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> @base</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-49">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-49">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>A reference has base part (<code>this</code> value) and name part.
We cache them separately for compiling complex expressions.
2014-01-29 23:54:00 -05:00
<code>a()[b()] ?= c</code> -&gt; <code>(_base = a())[_name = b()] ? _base[_name] = c</code></p>
</div>
2016-09-22 16:19:43 -04:00
<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.isComplex() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> name?.isComplex()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> [<span class="hljs-keyword">this</span>, <span class="hljs-keyword">this</span>] <span class="hljs-comment"># `a` `a.b`</span>
2016-09-22 16:19:43 -04:00
base = <span class="hljs-keyword">new</span> Value @base, @properties[...<span class="hljs-number">-1</span>]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> base.isComplex() <span class="hljs-comment"># `a().b`</span>
2016-09-22 16:19:43 -04:00
bref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'base'</span>
2014-01-29 23:54:00 -05:00
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.isComplex() <span class="hljs-comment"># `a[b()]`</span>
2016-09-22 16:19:43 -04:00
nref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'name'</span>
2014-01-29 23:54:00 -05:00
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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-50">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-50">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-01-29 23:54:00 -05:00
evaluate anything twice when building the soak chain.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@base.front = @front
props = @properties
fragments = @base.compileToFragments o, (<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">then</span> LEVEL_ACCESS <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>)
<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">and</span> SIMPLENUM.test fragmentsToText fragments
fragments.push @makeCode <span class="hljs-string">'.'</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props
2013-03-18 01:06:33 -04:00
fragments.push (prop.compileToFragments o)...
fragments</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-51">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-51">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -&gt; <code>a.b if a?</code></p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@unfoldedSoak ?= <span class="hljs-keyword">do</span> =&gt;
<span class="hljs-keyword">if</span> ifn = @base.unfoldSoak o
ifn.body.properties.push @properties...
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> ifn
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> @properties <span class="hljs-keyword">when</span> prop.soak
2014-01-29 23:54:00 -05:00
prop.soak = <span class="hljs-literal">off</span>
2016-09-22 16:19:43 -04:00
fst = <span class="hljs-keyword">new</span> Value @base, @properties[...i]
snd = <span class="hljs-keyword">new</span> Value @base, @properties[i..]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> fst.isComplex()
2016-09-22 16:19:43 -04:00
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
2014-01-29 23:54:00 -05:00
fst = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign ref, fst
2013-03-18 01:06:33 -04:00
snd.base = ref
2016-09-22 16:19:43 -04:00
<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>
2014-01-29 23:54:00 -05:00
<span class="hljs-literal">no</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-52">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-52">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="comment">Comment</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-53">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-53">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>CoffeeScript passes through block comments as JavaScript block comments
2014-01-29 23:54:00 -05:00
at the same position.</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Comment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@comment)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
isStatement: YES
makeReturn: THIS
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
comment = @comment.replace <span class="hljs-regexp">/^(\s*)#(?=\s)/gm</span>, <span class="hljs-string">"$1 *"</span>
code = <span class="hljs-string">"/*<span class="hljs-subst">#{multident comment, @tab}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> comment <span class="hljs-keyword">then</span> <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span> */"</span>
2014-01-29 23:54:00 -05:00
code = o.indent + code <span class="hljs-keyword">if</span> (level <span class="hljs-keyword">or</span> o.level) <span class="hljs-keyword">is</span> LEVEL_TOP
2016-09-22 16:19:43 -04:00
[@makeCode(<span class="hljs-string">"\n"</span>), @makeCode(code)]</pre></div></div>
2014-08-23 10:08:39 -04:00
</li>
<li id="section-54">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-54">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<h3 id="call">Call</h3>
</div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-55">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-55">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Node for a function invocation.</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Call = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Call</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @args = [], @soak)</span> -&gt;</span>
@isNew = <span class="hljs-literal">false</span>
<span class="hljs-keyword">if</span> @variable <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @variable.isNotCallable()
@variable.error <span class="hljs-string">"literal is not a function"</span>
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'args'</span>]</pre></div></div>
2014-01-29 23:54:00 -05:00
2013-06-02 01:37:45 -04:00
</li>
2014-08-23 10:08:39 -04:00
<li id="section-56">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-56">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Tag this invocation as creating a new instance.</p>
</div>
2016-09-22 16:19:43 -04:00
<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()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@isNew = <span class="hljs-literal">true</span>
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-57">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-57">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Soaked chained invocations unfold into if/else ternary structures.</p>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<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> <span class="hljs-keyword">this</span> <span class="hljs-keyword">instanceof</span> SuperCall
left = <span class="hljs-keyword">new</span> Literal @superReference o
2014-01-29 23:54:00 -05:00
rite = <span class="hljs-keyword">new</span> Value left
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> ifn <span class="hljs-keyword">if</span> ifn = unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'variable'</span>
[left, rite] = <span class="hljs-keyword">new</span> Value(@variable).cacheReference o
rite = <span class="hljs-keyword">new</span> Call rite, @args
rite.isNew = @isNew
2014-01-29 23:54:00 -05:00
left = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"typeof <span class="hljs-subst">#{ left.compile o }</span> === \"function\""</span>
2016-09-22 16:19:43 -04:00
<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>
2014-01-29 23:54:00 -05:00
call = <span class="hljs-keyword">this</span>
2013-03-18 01:06:33 -04:00
list = []
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">loop</span>
<span class="hljs-keyword">if</span> call.variable <span class="hljs-keyword">instanceof</span> Call
2013-03-18 01:06:33 -04:00
list.push call
call = call.variable
2014-01-29 23:54:00 -05:00
<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
2013-03-18 01:06:33 -04:00
list.push call
2014-01-29 23:54:00 -05:00
<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
2013-03-18 01:06:33 -04:00
call.variable = ifn
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
call.variable.base = ifn
2014-01-29 23:54:00 -05:00
ifn = unfoldSoak o, call, <span class="hljs-string">'variable'</span>
2013-03-18 01:06:33 -04:00
ifn</pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-58">
2013-03-18 01:06:33 -04:00
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-58">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Compile a vanilla function call.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@variable?.front = @front
compiledArray = Splat.compileSplattedArray o, @args, <span class="hljs-literal">true</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> compiledArray.length
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> @compileSplat o, compiledArray
2013-03-18 01:06:33 -04:00
compiledArgs = []
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> arg, argIndex <span class="hljs-keyword">in</span> @args
<span class="hljs-keyword">if</span> argIndex <span class="hljs-keyword">then</span> compiledArgs.push @makeCode <span class="hljs-string">", "</span>
2013-03-18 01:06:33 -04:00
compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
2013-03-04 14:19:08 -05:00
2013-03-18 01:06:33 -04:00
fragments = []
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">instanceof</span> SuperCall
preface = @superReference(o) + <span class="hljs-string">".call(<span class="hljs-subst">#{@superThis(o)}</span>"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> compiledArgs.length <span class="hljs-keyword">then</span> preface += <span class="hljs-string">", "</span>
2016-09-22 16:19:43 -04:00
fragments.push @makeCode preface
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @isNew <span class="hljs-keyword">then</span> fragments.push @makeCode <span class="hljs-string">'new '</span>
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @makeCode <span class="hljs-string">"("</span>
2013-03-18 01:06:33 -04:00
fragments.push compiledArgs...
2016-09-22 16:19:43 -04:00
fragments.push @makeCode <span class="hljs-string">")"</span>
2013-03-18 01:06:33 -04:00
fragments</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-59">
2013-03-18 01:06:33 -04:00
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-59">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>If you call a function with a splat, its converted into a JavaScript
2010-08-03 00:06:34 -04:00
<code>.apply()</code> call to allow an array of arguments to be passed.
2014-08-23 10:08:39 -04:00
If its a constructor, then things get real tricky. We have to inject an
2014-01-29 23:54:00 -05:00
inner constructor in order to be able to pass the varargs.</p>
2014-08-23 10:08:39 -04:00
<p>splatArgs is an array of CodeFragments to put into the apply.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileSplat: <span class="hljs-function"><span class="hljs-params">(o, splatArgs)</span> -&gt;</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">instanceof</span> SuperCall
<span class="hljs-keyword">return</span> [].concat @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ @superReference o }</span>.apply(<span class="hljs-subst">#{@superThis(o)}</span>, "</span>),
splatArgs, @makeCode(<span class="hljs-string">")"</span>)
2013-03-04 14:19:08 -05:00
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @isNew
idt = @tab + TAB
<span class="hljs-keyword">return</span> [].concat @makeCode(<span class="hljs-string">"""
2013-03-18 01:06:33 -04:00
(function(func, args, ctor) {
2014-01-29 23:54:00 -05:00
<span class="hljs-subst">#{idt}</span>ctor.prototype = func.prototype;
<span class="hljs-subst">#{idt}</span>var child = new ctor, result = func.apply(child, args);
<span class="hljs-subst">#{idt}</span>return Object(result) === result ? result : child;
2016-09-22 16:19:43 -04:00
<span class="hljs-subst">#{@tab}</span>})("""</span>),
(@variable.compileToFragments o, LEVEL_LIST),
@makeCode(<span class="hljs-string">", "</span>), splatArgs, @makeCode(<span class="hljs-string">", function(){})"</span>)
2013-03-04 14:19:08 -05:00
2013-03-18 01:06:33 -04:00
answer = []
2016-09-22 16:19:43 -04:00
base = <span class="hljs-keyword">new</span> Value @variable
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> (name = base.properties.pop()) <span class="hljs-keyword">and</span> base.isComplex()
ref = o.scope.freeVariable <span class="hljs-string">'ref'</span>
2016-09-22 16:19:43 -04:00
answer = answer.concat @makeCode(<span class="hljs-string">"(<span class="hljs-subst">#{ref}</span> = "</span>),
2013-03-18 01:06:33 -04:00
(base.compileToFragments o, LEVEL_LIST),
2016-09-22 16:19:43 -04:00
@makeCode(<span class="hljs-string">")"</span>),
2013-03-18 01:06:33 -04:00
name.compileToFragments(o)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
fun = base.compileToFragments o, LEVEL_ACCESS
2016-09-22 16:19:43 -04:00
fun = @wrapInBraces fun <span class="hljs-keyword">if</span> SIMPLENUM.test fragmentsToText fun
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> name
2013-03-18 01:06:33 -04:00
ref = fragmentsToText fun
fun.push (name.compileToFragments o)...
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
ref = <span class="hljs-string">'null'</span>
2013-03-18 01:06:33 -04:00
answer = answer.concat fun
2016-09-22 16:19:43 -04:00
answer = answer.concat @makeCode(<span class="hljs-string">".apply(<span class="hljs-subst">#{ref}</span>, "</span>), splatArgs, @makeCode(<span class="hljs-string">")"</span>)</pre></div></div>
</li>
<li id="section-60">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-60">&#182;</a>
</div>
<h3 id="super">Super</h3>
</div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-61">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-61">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Takes care of converting <code>super()</code> calls into calls against the prototypes
function of the same name.</p>
2014-08-23 10:08:39 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.SuperCall = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SuperCall</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(args)</span> -&gt;</span>
<span class="hljs-keyword">super</span> <span class="hljs-literal">null</span>, args ? [<span class="hljs-keyword">new</span> Splat <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span>]</pre></div></div>
2014-08-23 10:08:39 -04:00
</li>
<li id="section-62">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-62">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<p>Allow to recognize a bare <code>super</code> call without parentheses and arguments.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> @isBare = args?</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-63">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-63">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Grab the reference to the superclasss implementation of the current
method.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> superReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
method = o.scope.namedMethod()
<span class="hljs-keyword">if</span> method?.klass
{klass, name, variable} = method
<span class="hljs-keyword">if</span> klass.isComplex()
bref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.parent.freeVariable <span class="hljs-string">'base'</span>
base = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign bref, klass
variable.base = base
variable.properties.splice <span class="hljs-number">0</span>, klass.properties.length
<span class="hljs-keyword">if</span> name.isComplex() <span class="hljs-keyword">or</span> (name <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">and</span> name.index.isAssignable())
nref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.parent.freeVariable <span class="hljs-string">'name'</span>
name = <span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> Assign nref, name.index
variable.properties.pop()
variable.properties.push name
accesses = [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'__super__'</span>]
accesses.push <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'constructor'</span> <span class="hljs-keyword">if</span> method.static
accesses.push <span class="hljs-keyword">if</span> nref? <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index nref <span class="hljs-keyword">else</span> name
(<span class="hljs-keyword">new</span> Value bref ? klass, accesses).compile o
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method?.ctor
<span class="hljs-string">"<span class="hljs-subst">#{method.name}</span>.__super__.constructor"</span>
<span class="hljs-keyword">else</span>
@error <span class="hljs-string">'cannot call super outside of an instance method.'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2014-08-23 10:08:39 -04:00
<li id="section-64">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2014-08-23 10:08:39 -04:00
<a class="pilcrow" href="#section-64">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>The appropriate <code>this</code> value for a <code>super</code> call.</p>
2014-08-23 10:08:39 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> superThis : <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
method = o.scope.method
(method <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> method.klass <span class="hljs-keyword">and</span> method.context) <span class="hljs-keyword">or</span> <span class="hljs-string">"this"</span></pre></div></div>
2014-08-23 10:08:39 -04:00
</li>
<li id="section-65">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-65">&#182;</a>
</div>
2016-09-22 16:19:43 -04:00
<h3 id="regexwithinterpolations">RegexWithInterpolations</h3>
</div>
</li>
<li id="section-66">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-66">&#182;</a>
</div>
<p>Regexes with interpolations are in fact just a variation of a <code>Call</code> (a
<code>RegExp()</code> call to be precise) with a <code>StringWithInterpolations</code> inside.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.RegexWithInterpolations = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegexWithInterpolations</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Call</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(args = [])</span> -&gt;</span>
<span class="hljs-keyword">super</span> (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'RegExp'</span>), args, <span class="hljs-literal">false</span></pre></div></div>
</li>
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-67">&#182;</a>
</div>
<h3 id="extends">Extends</h3>
</div>
</li>
<li id="section-68">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-68">&#182;</a>
</div>
<p>Node to extend an objects prototype with an ancestor object.
After <code>goog.inherits</code> from the
<a href="http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html">Closure Library</a>.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Extends = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Extends</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@child, @parent)</span> -&gt;</span>
children: [<span class="hljs-string">'child'</span>, <span class="hljs-string">'parent'</span>]</pre></div></div>
</li>
<li id="section-69">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-69">&#182;</a>
</div>
<p>Hooks one constructor into anothers prototype chain.</p>
</div>
<div class="content"><div class='highlight'><pre> compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'extend'</span>, o), [@child, @parent]).compileToFragments o</pre></div></div>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">&#182;</a>
</div>
<h3 id="access">Access</h3>
</div>
</li>
<li id="section-71">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-71">&#182;</a>
</div>
2014-08-23 10:08:39 -04:00
<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>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Access = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Access</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@name, tag)</span> -&gt;</span>
@name.asKey = <span class="hljs-literal">yes</span>
@soak = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'soak'</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'name'</span>]
2016-09-22 16:19:43 -04:00
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
name = @name.compileToFragments o
node = @name.unwrap()
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> PropertyName
<span class="hljs-keyword">if</span> node.value <span class="hljs-keyword">in</span> JS_FORBIDDEN
[@makeCode(<span class="hljs-string">'["'</span>), name..., @makeCode(<span class="hljs-string">'"]'</span>)]
<span class="hljs-keyword">else</span>
[@makeCode(<span class="hljs-string">'.'</span>), name...]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
[@makeCode(<span class="hljs-string">'['</span>), name..., @makeCode(<span class="hljs-string">']'</span>)]
2016-09-22 16:19:43 -04:00
isComplex: NO</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-72">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-72">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="index">Index</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-73">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-73">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A <code>[ ... ]</code> indexed access into an array or object.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Index = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@index)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'index'</span>]
2016-09-22 16:19:43 -04:00
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[].concat @makeCode(<span class="hljs-string">"["</span>), @index.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">"]"</span>)
2016-09-22 16:19:43 -04:00
isComplex: <span class="hljs-function">-&gt;</span>
@index.isComplex()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-74">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-74">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="range">Range</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-75">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-75">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A range literal. Ranges can be used to extract portions (slices) of arrays,
2010-12-24 14:02:10 -05:00
to specify a range for comprehensions, or as a value, to be expanded into the
2014-01-29 23:54:00 -05:00
corresponding array of integers at runtime.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Range = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Range</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
2010-11-21 12:38:27 -05:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'from'</span>, <span class="hljs-string">'to'</span>]
2010-11-21 12:38:27 -05:00
2016-09-22 16:19:43 -04:00
constructor: <span class="hljs-function"><span class="hljs-params">(@from, @to, tag)</span> -&gt;</span>
@exclusive = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'exclusive'</span>
@equals = <span class="hljs-keyword">if</span> @exclusive <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'='</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-76">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-76">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Compiles the ranges source variables where it starts and where it ends.
2014-01-29 23:54:00 -05:00
But only if they need to be cached to avoid double evaluation.</p>
</div>
2016-09-22 16:19:43 -04:00
<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>
2015-02-18 15:43:33 -05:00
isComplex = del o, <span class="hljs-string">'isComplex'</span>
2016-09-22 16:19:43 -04:00
[@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST, isComplex
[@toC, @toVar] = @cacheToCodeFragments @to.cache o, LEVEL_LIST, isComplex
[@step, @stepVar] = @cacheToCodeFragments step.cache o, LEVEL_LIST, isComplex <span class="hljs-keyword">if</span> step = del o, <span class="hljs-string">'step'</span>
@fromNum = <span class="hljs-keyword">if</span> @from.isNumber() <span class="hljs-keyword">then</span> Number @fromVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>
@toNum = <span class="hljs-keyword">if</span> @to.isNumber() <span class="hljs-keyword">then</span> Number @toVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>
@stepNum = <span class="hljs-keyword">if</span> step?.isNumber() <span class="hljs-keyword">then</span> Number @stepVar <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-77">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-77">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>When compiled normally, the range returns the contents of the <em>for loop</em>
2014-01-29 23:54:00 -05:00
needed to iterate over the values in the range. Used by comprehensions.</p>
</div>
2016-09-22 16:19:43 -04:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-78">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-78">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Set up endpoints.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> known = @fromNum? <span class="hljs-keyword">and</span> @toNum?
2014-01-29 23:54:00 -05:00
idx = del o, <span class="hljs-string">'index'</span>
idxName = del o, <span class="hljs-string">'name'</span>
namedIndex = idxName <span class="hljs-keyword">and</span> idxName <span class="hljs-keyword">isnt</span> idx
2016-09-22 16:19:43 -04:00
varPart = <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{@fromC}</span>"</span>
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@toC}</span>"</span> <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar
varPart += <span class="hljs-string">", <span class="hljs-subst">#{@step}</span>"</span> <span class="hljs-keyword">if</span> @step <span class="hljs-keyword">isnt</span> @stepVar
[lt, gt] = [<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &lt;<span class="hljs-subst">#{@equals}</span>"</span>, <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> &gt;<span class="hljs-subst">#{@equals}</span>"</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-79">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-79">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Generate the condition.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> condPart = <span class="hljs-keyword">if</span> @stepNum?
<span class="hljs-keyword">if</span> @stepNum &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{@toVar}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{@toVar}</span>"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> known
2016-09-22 16:19:43 -04:00
[from, to] = [@fromNum, @toNum]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> from &lt;= to <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{to}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{to}</span>"</span>
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
cond = <span class="hljs-keyword">if</span> @stepVar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{@stepVar}</span> &gt; 0"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>"</span>
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{@toVar}</span> : <span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{@toVar}</span>"</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-80">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-80">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Generate the step.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> stepPart = <span class="hljs-keyword">if</span> @stepVar
<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> += <span class="hljs-subst">#{@stepVar}</span>"</span>
2014-01-29 23:54:00 -05:00
<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> from &lt;= to <span class="hljs-keyword">then</span> <span class="hljs-string">"++<span class="hljs-subst">#{idx}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"--<span class="hljs-subst">#{idx}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> from &lt;= to <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>++"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>--"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> namedIndex
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? ++<span class="hljs-subst">#{idx}</span> : --<span class="hljs-subst">#{idx}</span>"</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{idx}</span>++ : <span class="hljs-subst">#{idx}</span>--"</span>
2012-04-10 14:57:45 -04:00
2014-01-29 23:54:00 -05:00
varPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{varPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex
stepPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{stepPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-81">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-81">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>The final loop body.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> [@makeCode <span class="hljs-string">"<span class="hljs-subst">#{varPart}</span>; <span class="hljs-subst">#{condPart}</span>; <span class="hljs-subst">#{stepPart}</span>"</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-82">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-82">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>When used as a value, expand the range into the equivalent array.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileArray: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
known = @fromNum? <span class="hljs-keyword">and</span> @toNum?
<span class="hljs-keyword">if</span> known <span class="hljs-keyword">and</span> Math.abs(@fromNum - @toNum) &lt;= <span class="hljs-number">20</span>
range = [@fromNum..@toNum]
range.pop() <span class="hljs-keyword">if</span> @exclusive
<span class="hljs-keyword">return</span> [@makeCode <span class="hljs-string">"[<span class="hljs-subst">#{ range.join(<span class="hljs-string">', '</span>) }</span>]"</span>]
idt = @tab + TAB
i = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
2014-01-29 23:54:00 -05:00
result = o.scope.freeVariable <span class="hljs-string">'results'</span>
pre = <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{result}</span> = [];"</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> known
2013-03-18 01:06:33 -04:00
o.index = i
2016-09-22 16:19:43 -04:00
body = fragmentsToText @compileNode o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
vars = <span class="hljs-string">"<span class="hljs-subst">#{i}</span> = <span class="hljs-subst">#{@fromC}</span>"</span> + <span class="hljs-keyword">if</span> @toC <span class="hljs-keyword">isnt</span> @toVar <span class="hljs-keyword">then</span> <span class="hljs-string">", <span class="hljs-subst">#{@toC}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
cond = <span class="hljs-string">"<span class="hljs-subst">#{@fromVar}</span> &lt;= <span class="hljs-subst">#{@toVar}</span>"</span>
body = <span class="hljs-string">"var <span class="hljs-subst">#{vars}</span>; <span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{i}</span> &lt;<span class="hljs-subst">#{@equals}</span> <span class="hljs-subst">#{@toVar}</span> : <span class="hljs-subst">#{i}</span> &gt;<span class="hljs-subst">#{@equals}</span> <span class="hljs-subst">#{@toVar}</span>; <span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{i}</span>++ : <span class="hljs-subst">#{i}</span>--"</span>
2014-01-29 23:54:00 -05:00
post = <span class="hljs-string">"{ <span class="hljs-subst">#{result}</span>.push(<span class="hljs-subst">#{i}</span>); }\n<span class="hljs-subst">#{idt}</span>return <span class="hljs-subst">#{result}</span>;\n<span class="hljs-subst">#{o.indent}</span>"</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-function"> <span class="hljs-title">hasArgs</span> = <span class="hljs-params">(node)</span> -&gt;</span> node?.contains isLiteralArguments
args = <span class="hljs-string">', arguments'</span> <span class="hljs-keyword">if</span> hasArgs(@from) <span class="hljs-keyword">or</span> hasArgs(@to)
[@makeCode <span class="hljs-string">"(function() {<span class="hljs-subst">#{pre}</span>\n<span class="hljs-subst">#{idt}</span>for (<span class="hljs-subst">#{body}</span>)<span class="hljs-subst">#{post}</span>}).apply(this<span class="hljs-subst">#{args ? <span class="hljs-string">''</span>}</span>)"</span>]</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-83">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-83">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<h3 id="slice">Slice</h3>
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-84">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-84">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>An array slice literal. Unlike JavaScripts <code>Array#slice</code>, the second parameter
2010-12-24 14:02:10 -05:00
specifies the index of the end of the slice, just as the first parameter
2014-01-29 23:54:00 -05:00
is the index of the beginning.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Slice = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Slice</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
2010-11-21 12:38:27 -05:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'range'</span>]
2010-11-21 12:38:27 -05:00
2016-09-22 16:19:43 -04:00
constructor: <span class="hljs-function"><span class="hljs-params">(@range)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">super</span>()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-85">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-85">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>We have to be careful when trying to slice through the end of the array,
2010-12-24 14:02:10 -05:00
<code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>.
2014-01-29 23:54:00 -05:00
<code>9e9</code> should be safe because <code>9e9</code> &gt; <code>2**32</code>, the max array length.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{to, from} = @range
fromCompiled = from <span class="hljs-keyword">and</span> from.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">or</span> [@makeCode <span class="hljs-string">'0'</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-86">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-86">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>TODO: jwalton - move this into the if?</p>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> to
2013-03-18 01:06:33 -04:00
compiled = to.compileToFragments o, LEVEL_PAREN
compiledText = fragmentsToText compiled
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">not</span> @range.exclusive <span class="hljs-keyword">and</span> +compiledText <span class="hljs-keyword">is</span> <span class="hljs-number">-1</span>)
toStr = <span class="hljs-string">', '</span> + <span class="hljs-keyword">if</span> @range.exclusive
2013-03-18 01:06:33 -04:00
compiledText
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> to.isNumber()
2014-01-29 23:54:00 -05:00
<span class="hljs-string">"<span class="hljs-subst">#{+compiledText + <span class="hljs-number">1</span>}</span>"</span>
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
compiled = to.compileToFragments o, LEVEL_ACCESS
2014-01-29 23:54:00 -05:00
<span class="hljs-string">"+<span class="hljs-subst">#{fragmentsToText compiled}</span> + 1 || 9e9"</span>
2016-09-22 16:19:43 -04:00
[@makeCode <span class="hljs-string">".slice(<span class="hljs-subst">#{ fragmentsToText fromCompiled }</span><span class="hljs-subst">#{ toStr <span class="hljs-keyword">or</span> <span class="hljs-string">''</span> }</span>)"</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-87">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-87">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="obj">Obj</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-88">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-88">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>An object literal, nothing fancy.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Obj = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Obj</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(props, @generated = <span class="hljs-literal">false</span>)</span> -&gt;</span>
@objects = @properties = props <span class="hljs-keyword">or</span> []
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'properties'</span>]
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
props = @properties
<span class="hljs-keyword">if</span> @generated
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> node <span class="hljs-keyword">instanceof</span> Value
node.error <span class="hljs-string">'cannot have an implicit value in an implicit object'</span>
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">break</span> <span class="hljs-keyword">for</span> prop, dynamicIndex <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> (prop.variable <span class="hljs-keyword">or</span> prop).base <span class="hljs-keyword">instanceof</span> Parens
hasDynamic = dynamicIndex &lt; props.length
2013-03-18 01:06:33 -04:00
idt = o.indent += TAB
2016-09-22 16:19:43 -04:00
lastNoncom = @lastNonComment @properties
2013-03-18 01:06:33 -04:00
answer = []
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> hasDynamic
oref = o.scope.freeVariable <span class="hljs-string">'obj'</span>
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">"(\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span> = "</span>
answer.push @makeCode <span class="hljs-string">"{<span class="hljs-subst">#{<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> dynamicIndex <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'}'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'\n'</span>}</span>"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> dynamicIndex
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span>}"</span> <span class="hljs-keyword">unless</span> i <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
answer.push @makeCode <span class="hljs-string">',\n'</span>
2015-02-18 15:43:33 -05:00
join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> i <span class="hljs-keyword">is</span> dynamicIndex - <span class="hljs-number">1</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-string">''</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">is</span> lastNoncom <span class="hljs-keyword">or</span> prop <span class="hljs-keyword">instanceof</span> Comment
<span class="hljs-string">'\n'</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">',\n'</span>
indent = <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> idt
2015-02-18 15:43:33 -05:00
indent += TAB <span class="hljs-keyword">if</span> hasDynamic <span class="hljs-keyword">and</span> i &lt; dynamicIndex
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign
<span class="hljs-keyword">if</span> prop.context <span class="hljs-keyword">isnt</span> <span class="hljs-string">'object'</span>
prop.operatorToken.error <span class="hljs-string">"unexpected <span class="hljs-subst">#{prop.operatorToken.value}</span>"</span>
<span class="hljs-keyword">if</span> prop.variable <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> prop.variable.hasProperties()
prop.variable.error <span class="hljs-string">'invalid object key'</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> prop.<span class="hljs-keyword">this</span>
prop = <span class="hljs-keyword">new</span> Assign prop.properties[<span class="hljs-number">0</span>].name, prop, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> i &lt; dynamicIndex
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Assign
prop = <span class="hljs-keyword">new</span> Assign prop, prop, <span class="hljs-string">'object'</span>
(prop.variable.base <span class="hljs-keyword">or</span> prop.variable).asKey = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign
key = prop.variable
value = prop.value
<span class="hljs-keyword">else</span>
[key, value] = prop.base.cache o
2016-09-22 16:19:43 -04:00
prop = <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> IdentifierLiteral oref), [<span class="hljs-keyword">new</span> Access key]), value
<span class="hljs-keyword">if</span> indent <span class="hljs-keyword">then</span> answer.push @makeCode indent
2013-03-18 01:06:33 -04:00
answer.push prop.compileToFragments(o, LEVEL_TOP)...
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> join <span class="hljs-keyword">then</span> answer.push @makeCode join
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> hasDynamic
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">",\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span>\n<span class="hljs-subst">#{@tab}</span>)"</span>
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span> <span class="hljs-keyword">unless</span> props.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> hasDynamic <span class="hljs-keyword">then</span> @wrapInBraces answer <span class="hljs-keyword">else</span> answer
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
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>
2014-01-29 23:54:00 -05:00
<span class="hljs-literal">no</span></pre></div></div>
2013-03-18 01:06:33 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-89">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-89">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="arr">Arr</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-90">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-90">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>An array literal.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Arr = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Arr</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(objs)</span> -&gt;</span>
@objects = objs <span class="hljs-keyword">or</span> []
2010-08-04 23:14:34 -04:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'objects'</span>]
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">return</span> [@makeCode <span class="hljs-string">'[]'</span>] <span class="hljs-keyword">unless</span> @objects.length
2013-03-18 01:06:33 -04:00
o.indent += TAB
2016-09-22 16:19:43 -04:00
answer = Splat.compileSplattedArray o, @objects
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> answer <span class="hljs-keyword">if</span> answer.length
2013-03-04 14:19:08 -05:00
2013-03-18 01:06:33 -04:00
answer = []
2016-09-22 16:19:43 -04:00
compiledObjs = (obj.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> @objects)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledObjs
<span class="hljs-keyword">if</span> index
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">", "</span>
2013-03-18 01:06:33 -04:00
answer.push fragments...
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> fragmentsToText(answer).indexOf(<span class="hljs-string">'\n'</span>) &gt;= <span class="hljs-number">0</span>
2016-09-22 16:19:43 -04:00
answer.unshift @makeCode <span class="hljs-string">"[\n<span class="hljs-subst">#{o.indent}</span>"</span>
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>]"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
answer.unshift @makeCode <span class="hljs-string">"["</span>
answer.push @makeCode <span class="hljs-string">"]"</span>
2013-03-18 01:06:33 -04:00
answer
2016-09-22 16:19:43 -04:00
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>
2014-01-29 23:54:00 -05:00
<span class="hljs-literal">no</span></pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-91">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-91">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="class">Class</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-92">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-92">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>The CoffeeScript class definition.
2010-12-24 14:02:10 -05:00
Initialize a <strong>Class</strong> with its name, an optional superclass, and a
2014-01-29 23:54:00 -05:00
list of prototype property assignments.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Class = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @parent, @body = <span class="hljs-keyword">new</span> Block)</span> -&gt;</span>
@boundFuncs = []
@body.classBody = <span class="hljs-literal">yes</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'parent'</span>, <span class="hljs-string">'body'</span>]
defaultClassVariableName: <span class="hljs-string">'_Class'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-93">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-93">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Figure out the appropriate name for the constructor function of this class.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> determineName: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">return</span> @defaultClassVariableName <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
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@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> @defaultClassVariableName
name = node.value
<span class="hljs-keyword">unless</span> tail
message = isUnassignable name
@variable.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN <span class="hljs-keyword">then</span> <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">else</span> name</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-94">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-94">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>For all <code>this</code>-references and bound functions in the class definition,
2014-01-29 23:54:00 -05:00
<code>this</code> is the Class being constructed.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> setContext: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@body.traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">if</span> node.classBody
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> ThisLiteral
2013-03-18 01:06:33 -04:00
node.value = name
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code
node.context = name <span class="hljs-keyword">if</span> node.bound</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-95">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-95">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Ensure that all functions bound to the instance are proxied in the
2014-01-29 23:54:00 -05:00
constructor.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> addBoundFunctions: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">for</span> bvar <span class="hljs-keyword">in</span> @boundFuncs
lhs = (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> ThisLiteral), [<span class="hljs-keyword">new</span> Access bvar]).compile o
@ctor.body.unshift <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{lhs}</span> = <span class="hljs-subst">#{utility <span class="hljs-string">'bind'</span>, o}</span>(<span class="hljs-subst">#{lhs}</span>, this)"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-96">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-96">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Merge the properties from a top-level object as prototypal properties
2014-01-29 23:54:00 -05:00
on the class.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> addProperties: <span class="hljs-function"><span class="hljs-params">(node, name, o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
props = node.base.properties[..]
2014-01-29 23:54:00 -05:00
exprs = <span class="hljs-keyword">while</span> assign = props.shift()
<span class="hljs-keyword">if</span> assign <span class="hljs-keyword">instanceof</span> Assign
2013-03-18 01:06:33 -04:00
base = assign.variable.base
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">delete</span> assign.context
2013-03-18 01:06:33 -04:00
func = assign.value
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> base.value <span class="hljs-keyword">is</span> <span class="hljs-string">'constructor'</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @ctor
2014-01-29 23:54:00 -05:00
assign.error <span class="hljs-string">'cannot define more than one constructor in a class'</span>
<span class="hljs-keyword">if</span> func.bound
assign.error <span class="hljs-string">'cannot define a constructor as a bound function'</span>
<span class="hljs-keyword">if</span> func <span class="hljs-keyword">instanceof</span> Code
2016-09-22 16:19:43 -04:00
assign = @ctor = func
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@externalCtor = o.classScope.freeVariable <span class="hljs-string">'ctor'</span>
assign = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> IdentifierLiteral(@externalCtor), func
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> assign.variable.<span class="hljs-keyword">this</span>
func.static = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
2015-02-18 15:43:33 -05:00
acc = <span class="hljs-keyword">if</span> base.isComplex() <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index base <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Access base
2016-09-22 16:19:43 -04:00
assign.variable = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> IdentifierLiteral(name), [(<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'prototype'</span>), acc])
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> func <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> func.bound
2016-09-22 16:19:43 -04:00
@boundFuncs.push base
2014-01-29 23:54:00 -05:00
func.bound = <span class="hljs-literal">no</span>
2013-03-18 01:06:33 -04:00
assign
compact exprs</pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-97">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-97">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Walk the body of the class, looking for prototype properties to be converted
and tagging static assignments.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> walkBody: <span class="hljs-function"><span class="hljs-params">(name, o)</span> -&gt;</span>
@traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =&gt;</span>
2014-01-29 23:54:00 -05:00
cont = <span class="hljs-literal">true</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">if</span> child <span class="hljs-keyword">instanceof</span> Block
<span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> exps = child.expressions
<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.static = <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> Value <span class="hljs-keyword">and</span> node.isObject(<span class="hljs-literal">true</span>)
cont = <span class="hljs-literal">false</span>
2016-09-22 16:19:43 -04:00
exps[i] = @addProperties node, name, o
2013-03-18 01:06:33 -04:00
child.expressions = exps = flatten exps
2014-01-29 23:54:00 -05:00
cont <span class="hljs-keyword">and</span> child <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Class</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-98">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-98">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p><code>use strict</code> (and other directives) must be the first expression statement(s)
2012-04-10 14:57:45 -04:00
of a function body. This method ensures the prologue is correctly positioned
2014-01-29 23:54:00 -05:00
above the <code>constructor</code>.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> hoistDirectivePrologue: <span class="hljs-function">-&gt;</span>
2014-01-29 23:54:00 -05:00
index = <span class="hljs-number">0</span>
2016-09-22 16:19:43 -04:00
{expressions} = @body
2014-01-29 23:54:00 -05:00
++index <span class="hljs-keyword">while</span> (node = expressions[index]) <span class="hljs-keyword">and</span> node <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-keyword">or</span>
node <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> node.isString()
2016-09-22 16:19:43 -04:00
@directives = expressions.splice <span class="hljs-number">0</span>, index</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-99">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-99">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Make sure that a constructor is defined for the class, and properly
2014-01-29 23:54:00 -05:00
configured.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> ensureConstructor: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @ctor
@ctor = <span class="hljs-keyword">new</span> Code
<span class="hljs-keyword">if</span> @externalCtor
@ctor.body.push <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{@externalCtor}</span>.apply(this, arguments)"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @parent
@ctor.body.push <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{name}</span>.__super__.constructor.apply(this, arguments)"</span>
@ctor.body.makeReturn()
@body.expressions.unshift @ctor
@ctor.ctor = @ctor.name = name
@ctor.klass = <span class="hljs-literal">null</span>
@ctor.noReturn = <span class="hljs-literal">yes</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-100">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-100">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Instead of generating the JavaScript string directly, we build up the
2010-12-24 14:02:10 -05:00
equivalent syntax tree and compile that, in pieces. You can see the
2014-01-29 23:54:00 -05:00
constructor, property assignments, and inheritance getting built out below.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> jumpNode = @body.jumps()
2014-01-29 23:54:00 -05:00
jumpNode.error <span class="hljs-string">'Class bodies cannot contain pure statements'</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> argumentsNode = @body.contains isLiteralArguments
2014-01-29 23:54:00 -05:00
argumentsNode.error <span class="hljs-string">"Class bodies shouldn't reference arguments"</span>
2016-09-22 16:19:43 -04:00
name = @determineName()
lname = <span class="hljs-keyword">new</span> IdentifierLiteral name
func = <span class="hljs-keyword">new</span> Code [], Block.wrap [@body]
2014-01-29 23:54:00 -05:00
args = []
o.classScope = func.makeScope o.scope
2016-09-22 16:19:43 -04:00
@hoistDirectivePrologue()
@setContext name
@walkBody name, o
@ensureConstructor name
@addBoundFunctions o
@body.spaced = <span class="hljs-literal">yes</span>
@body.expressions.push lname
<span class="hljs-keyword">if</span> @parent
superClass = <span class="hljs-keyword">new</span> IdentifierLiteral o.classScope.freeVariable <span class="hljs-string">'superClass'</span>, reserve: <span class="hljs-literal">no</span>
@body.expressions.unshift <span class="hljs-keyword">new</span> Extends lname, superClass
2014-01-29 23:54:00 -05:00
func.params.push <span class="hljs-keyword">new</span> Param superClass
2016-09-22 16:19:43 -04:00
args.push @parent
2012-04-10 14:57:45 -04:00
2016-09-22 16:19:43 -04:00
@body.expressions.unshift @directives...
2013-06-02 01:37:45 -04:00
2014-01-29 23:54:00 -05:00
klass = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Call func, args
2016-09-22 16:19:43 -04:00
klass = <span class="hljs-keyword">new</span> Assign @variable, klass, <span class="hljs-literal">null</span>, { @moduleDeclaration } <span class="hljs-keyword">if</span> @variable
2014-01-29 23:54:00 -05:00
klass.compileToFragments o</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-101">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-101">&#182;</a>
</div>
<h3 id="import-and-export">Import and Export</h3>
</div>
<div class="content"><div class='highlight'><pre>
exports.ModuleDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@clause, @source)</span> -&gt;</span>
@checkSource()
children: [<span class="hljs-string">'clause'</span>, <span class="hljs-string">'source'</span>]
isStatement: YES
jumps: THIS
makeReturn: THIS
checkSource: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @source? <span class="hljs-keyword">and</span> @source <span class="hljs-keyword">instanceof</span> StringWithInterpolations
@source.error <span class="hljs-string">'the name of the module to be imported from must be an uninterpolated string'</span>
checkScope: <span class="hljs-function"><span class="hljs-params">(o, moduleDeclarationType)</span> -&gt;</span>
<span class="hljs-keyword">if</span> o.indent.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
@error <span class="hljs-string">"<span class="hljs-subst">#{moduleDeclarationType}</span> statements must be at top-level scope"</span>
exports.ImportDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleDeclaration</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o, <span class="hljs-string">'import'</span>
o.importedSymbols = []
code = []
code.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>import "</span>
code.push @clause.compileNode(o)... <span class="hljs-keyword">if</span> @clause?
<span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">' from '</span> <span class="hljs-keyword">unless</span> @clause <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>
code.push @makeCode @source.value
code.push @makeCode <span class="hljs-string">';'</span>
code
exports.ImportClause = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportClause</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@defaultBinding, @namedImports)</span> -&gt;</span>
children: [<span class="hljs-string">'defaultBinding'</span>, <span class="hljs-string">'namedImports'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = []
<span class="hljs-keyword">if</span> @defaultBinding?
code.push @defaultBinding.compileNode(o)...
code.push @makeCode <span class="hljs-string">', '</span> <span class="hljs-keyword">if</span> @namedImports?
<span class="hljs-keyword">if</span> @namedImports?
code.push @namedImports.compileNode(o)...
code
exports.ExportDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleDeclaration</span></span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@checkScope o, <span class="hljs-string">'export'</span>
code = []
code.push @makeCode <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>export "</span>
code.push @makeCode <span class="hljs-string">'default '</span> <span class="hljs-keyword">if</span> @ <span class="hljs-keyword">instanceof</span> ExportDefaultDeclaration
<span class="hljs-keyword">if</span> @ <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> ExportDefaultDeclaration <span class="hljs-keyword">and</span>
(@clause <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">or</span> @clause <span class="hljs-keyword">instanceof</span> Class)</pre></div></div>
</li>
<li id="section-102">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-102">&#182;</a>
</div>
<p>When the ES2015 <code>class</code> keyword is supported, dont add a <code>var</code> here</p>
</div>
<div class="content"><div class='highlight'><pre> code.push @makeCode <span class="hljs-string">'var '</span>
@clause.moduleDeclaration = <span class="hljs-string">'export'</span>
<span class="hljs-keyword">if</span> @clause.body? <span class="hljs-keyword">and</span> @clause.body <span class="hljs-keyword">instanceof</span> Block
code = code.concat @clause.compileToFragments o, LEVEL_TOP
<span class="hljs-keyword">else</span>
code = code.concat @clause.compileNode o
code.push @makeCode <span class="hljs-string">" from <span class="hljs-subst">#{@source.value}</span>"</span> <span class="hljs-keyword">if</span> @source?.value?
code.push @makeCode <span class="hljs-string">';'</span>
code
exports.ExportNamedDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportNamedDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ExportDefaultDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportDefaultDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ExportAllDeclaration = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportAllDeclaration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ExportDeclaration</span></span>
exports.ModuleSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@specifiers)</span> -&gt;</span>
children: [<span class="hljs-string">'specifiers'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
code = []
o.indent += TAB
compiledList = (specifier.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> specifier <span class="hljs-keyword">in</span> @specifiers)
<span class="hljs-keyword">if</span> @specifiers.length <span class="hljs-keyword">isnt</span> <span class="hljs-number">0</span>
code.push @makeCode <span class="hljs-string">"{\n<span class="hljs-subst">#{o.indent}</span>"</span>
<span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledList
code.push @makeCode(<span class="hljs-string">",\n<span class="hljs-subst">#{o.indent}</span>"</span>) <span class="hljs-keyword">if</span> index
code.push fragments...
code.push @makeCode <span class="hljs-string">"\n}"</span>
<span class="hljs-keyword">else</span>
code.push @makeCode <span class="hljs-string">'{}'</span>
code
exports.ImportSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifierList</span></span>
exports.ExportSpecifierList = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportSpecifierList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifierList</span></span>
exports.ModuleSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModuleSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@original, @alias, @moduleDeclarationType)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-103">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-103">&#182;</a>
</div>
<p>The name of the variable entering the local scope</p>
</div>
<div class="content"><div class='highlight'><pre> @identifier = <span class="hljs-keyword">if</span> @alias? <span class="hljs-keyword">then</span> @alias.value <span class="hljs-keyword">else</span> @original.value
children: [<span class="hljs-string">'original'</span>, <span class="hljs-string">'alias'</span>]
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o.scope.add @identifier, @moduleDeclarationType
code = []
code.push @makeCode @original.value
code.push @makeCode <span class="hljs-string">" as <span class="hljs-subst">#{@alias.value}</span>"</span> <span class="hljs-keyword">if</span> @alias?
code
exports.ImportSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifier</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(imported, local)</span> -&gt;</span>
<span class="hljs-keyword">super</span> imported, local, <span class="hljs-string">'import'</span>
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
<li id="section-104">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-104">&#182;</a>
</div>
<p>Per the spec, symbols cant be imported multiple times
(e.g. <code>import { foo, foo } from &#39;lib&#39;</code> is invalid)</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @identifier <span class="hljs-keyword">in</span> o.importedSymbols <span class="hljs-keyword">or</span> o.scope.check(@identifier)
@error <span class="hljs-string">"'<span class="hljs-subst">#{@identifier}</span>' has already been declared"</span>
<span class="hljs-keyword">else</span>
o.importedSymbols.push @identifier
<span class="hljs-keyword">super</span> o
exports.ImportDefaultSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportDefaultSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ImportSpecifier</span></span>
exports.ImportNamespaceSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImportNamespaceSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ImportSpecifier</span></span>
exports.ExportSpecifier = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExportSpecifier</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ModuleSpecifier</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(local, exported)</span> -&gt;</span>
<span class="hljs-keyword">super</span> local, exported, <span class="hljs-string">'export'</span></pre></div></div>
</li>
<li id="section-105">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-105">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="assign">Assign</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-106">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-106">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the
2016-09-22 16:19:43 -04:00
property of an object including within object literals.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Assign = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Assign</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@variable, @value, @context, options = {})</span> -&gt;</span>
{@param, @subpattern, @operatorToken, @moduleDeclaration} = options
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'value'</span>]
2016-09-22 16:19:43 -04:00
isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">and</span> @context? <span class="hljs-keyword">and</span> (@moduleDeclaration <span class="hljs-keyword">or</span> <span class="hljs-string">"?"</span> <span class="hljs-keyword">in</span> @context)
2011-08-04 23:17:23 -04:00
2016-09-22 16:19:43 -04:00
checkAssignability: <span class="hljs-function"><span class="hljs-params">(o, varBase)</span> -&gt;</span>
<span class="hljs-keyword">if</span> Object::hasOwnProperty.call(o.scope.positions, varBase.value) <span class="hljs-keyword">and</span>
o.scope.variables[o.scope.positions[varBase.value]].type <span class="hljs-keyword">is</span> <span class="hljs-string">'import'</span>
varBase.error <span class="hljs-string">"'<span class="hljs-subst">#{varBase.value}</span>' is read-only"</span>
2016-09-22 16:19:43 -04:00
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@[<span class="hljs-keyword">if</span> @context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'value'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'variable'</span>].assigns name
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'variable'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-107">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-107">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Compile an assignment, delegating to <code>compilePatternMatch</code> or
2010-12-24 14:02:10 -05:00
<code>compileSplice</code> if appropriate. Keep track of the name of the base object
2014-08-23 10:08:39 -04:00
weve been assigned to, for correct internal references. If the variable
2014-01-29 23:54:00 -05:00
has not been seen yet within the current scope, declare it.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> isValue = @variable <span class="hljs-keyword">instanceof</span> Value
<span class="hljs-keyword">return</span> @compilePatternMatch o <span class="hljs-keyword">if</span> @variable.isArray() <span class="hljs-keyword">or</span> @variable.isObject()
<span class="hljs-keyword">return</span> @compileSplice o <span class="hljs-keyword">if</span> @variable.isSplice()
<span class="hljs-keyword">return</span> @compileConditional o <span class="hljs-keyword">if</span> @context <span class="hljs-keyword">in</span> [<span class="hljs-string">'||='</span>, <span class="hljs-string">'&amp;&amp;='</span>, <span class="hljs-string">'?='</span>]
<span class="hljs-keyword">return</span> @compileSpecialMath o <span class="hljs-keyword">if</span> @context <span class="hljs-keyword">in</span> [<span class="hljs-string">'**='</span>, <span class="hljs-string">'//='</span>, <span class="hljs-string">'%%='</span>]
<span class="hljs-keyword">if</span> @value <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">if</span> @value.static
@value.klass = @variable.base
@value.name = @variable.properties[<span class="hljs-number">0</span>]
@value.variable = @variable
<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
2015-02-18 15:43:33 -05:00
<span class="hljs-keyword">if</span> prototype.name?.value <span class="hljs-keyword">is</span> <span class="hljs-string">'prototype'</span>
2016-09-22 16:19:43 -04:00
@value.klass = <span class="hljs-keyword">new</span> Value @variable.base, properties
@value.name = name
@value.variable = @variable
<span class="hljs-keyword">unless</span> @context
varBase = @variable.unwrapAll()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">unless</span> varBase.isAssignable()
2016-09-22 16:19:43 -04:00
@variable.error <span class="hljs-string">"'<span class="hljs-subst">#{@variable.compile o}</span>' can't be assigned"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">unless</span> varBase.hasProperties?()
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @moduleDeclaration <span class="hljs-comment"># `moduleDeclaration` can be `'import'` or `'export'`</span>
@checkAssignability o, varBase
o.scope.add varBase.value, @moduleDeclaration
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @param
2015-02-18 15:43:33 -05:00
o.scope.add varBase.value, <span class="hljs-string">'var'</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@checkAssignability o, varBase
2015-02-18 15:43:33 -05:00
o.scope.find varBase.value
2016-09-22 16:19:43 -04:00
val = @value.compileToFragments o, LEVEL_LIST
@variable.front = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> isValue <span class="hljs-keyword">and</span> @variable.base <span class="hljs-keyword">instanceof</span> Obj
compiledName = @variable.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">if</span> @context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> fragmentsToText(compiledName) <span class="hljs-keyword">in</span> JS_FORBIDDEN
compiledName.unshift @makeCode <span class="hljs-string">'"'</span>
compiledName.push @makeCode <span class="hljs-string">'"'</span>
<span class="hljs-keyword">return</span> compiledName.concat @makeCode(<span class="hljs-string">": "</span>), val
answer = compiledName.concat @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{ @context <span class="hljs-keyword">or</span> <span class="hljs-string">'='</span> }</span> "</span>), val
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_LIST <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> @wrapInBraces answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-108">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-108">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Brief implementation of recursive pattern matching, when assigning array or
2015-09-03 12:37:36 -04:00
object literals to a value. Peeks at their properties to assign inner names.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compilePatternMatch: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP
{value} = <span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
{objects} = @variable.base
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">unless</span> olen = objects.length
2013-03-18 01:06:33 -04:00
code = value.compileToFragments o
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_OP <span class="hljs-keyword">then</span> @wrapInBraces code <span class="hljs-keyword">else</span> code
2015-09-03 12:37:36 -04:00
[obj] = objects
<span class="hljs-keyword">if</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">'Destructuring assignment has no target'</span>
2016-09-22 16:19:43 -04:00
isObject = @variable.isObject()
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">if</span> top <span class="hljs-keyword">and</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Splat</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-109">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-109">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2015-09-03 12:37:36 -04:00
<p>Pick the property straight off the value when theres just one to pick
(no need to cache the value into a variable).</p>
2014-01-29 23:54:00 -05:00
</div>
2015-09-03 12:37:36 -04:00
<div class="content"><div class='highlight'><pre> defaultValue = <span class="hljs-literal">null</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-110">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-110">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2015-09-03 12:37:36 -04:00
<p>A regular object pattern-match.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> {variable: {base: idx}, value: obj} = obj
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
idx = <span class="hljs-keyword">if</span> isObject</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-111">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-111">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2015-09-03 12:37:36 -04:00
<p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
obj.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName obj.unwrap().value
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">else</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-112">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-112">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2015-09-03 12:37:36 -04:00
<p>A regular array pattern-match.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> NumberLiteral <span class="hljs-number">0</span>
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
2015-09-03 12:37:36 -04:00
value = <span class="hljs-keyword">new</span> Value value
value.properties.push <span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> acc <span class="hljs-keyword">then</span> Access <span class="hljs-keyword">else</span> Index) idx
2016-09-22 16:19:43 -04:00
message = isUnassignable obj.unwrap().value
obj.error message <span class="hljs-keyword">if</span> message
2015-09-03 12:37:36 -04:00
value = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, value, defaultValue <span class="hljs-keyword">if</span> defaultValue
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Assign(obj, value, <span class="hljs-literal">null</span>, param: @param).compileToFragments o, LEVEL_TOP
2015-09-03 12:37:36 -04:00
vvar = value.compileToFragments o, LEVEL_LIST
vvarText = fragmentsToText vvar
assigns = []
expandedIdx = <span class="hljs-literal">false</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-113">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-113">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2015-09-03 12:37:36 -04:00
<p>Make vvar into a simple variable if it isnt already.</p>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<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)
assigns.push [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ ref = o.scope.freeVariable <span class="hljs-string">'ref'</span> }</span> = "</span>), vvar...]
vvar = [@makeCode ref]
2015-09-03 12:37:36 -04:00
vvarText = ref
<span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects
idx = i
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Splat
2013-03-18 01:06:33 -04:00
name = obj.name.unwrap().value
obj = obj.unwrap()
2015-01-29 12:20:46 -05:00
val = <span class="hljs-string">"<span class="hljs-subst">#{olen}</span> &lt;= <span class="hljs-subst">#{vvarText}</span>.length ? <span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call(<span class="hljs-subst">#{vvarText}</span>, <span class="hljs-subst">#{i}</span>"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> rest = olen - i - <span class="hljs-number">1</span>
2016-09-22 16:19:43 -04:00
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
2014-01-29 23:54:00 -05:00
val += <span class="hljs-string">", <span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>) : (<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{i}</span>, [])"</span>
<span class="hljs-keyword">else</span>
val += <span class="hljs-string">") : []"</span>
val = <span class="hljs-keyword">new</span> Literal val
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion
<span class="hljs-keyword">if</span> rest = olen - i - <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> rest <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{vvarText}</span>.length - 1"</span>
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
2014-01-29 23:54:00 -05:00
val = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>"</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>
assigns.push val.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">or</span> obj <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">"multiple splats/expansions are disallowed in an assignment"</span>
2015-09-03 12:37:36 -04:00
defaultValue = <span class="hljs-literal">null</span>
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> obj.context <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span></pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-114">
2015-09-03 12:37:36 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-114">&#182;</a>
2015-09-03 12:37:36 -04:00
</div>
<p>A regular object pattern-match.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> {variable: {base: idx}, value: obj} = obj
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign
defaultValue = obj.value
obj = obj.variable
idx = <span class="hljs-keyword">if</span> isObject</pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-115">
2015-09-03 12:37:36 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-115">&#182;</a>
2015-09-03 12:37:36 -04:00
</div>
<p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
obj.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> PropertyName obj.unwrap().value
2015-09-03 12:37:36 -04:00
<span class="hljs-keyword">else</span></pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-116">
2015-09-03 12:37:36 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-116">&#182;</a>
2015-09-03 12:37:36 -04:00
</div>
<p>A regular array pattern-match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> Literal expandedIdx <span class="hljs-keyword">or</span> idx
name = obj.unwrap().value
2016-09-22 16:19:43 -04:00
acc = idx.unwrap() <span class="hljs-keyword">instanceof</span> PropertyName
2014-01-29 23:54:00 -05:00
val = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(vvarText), [<span class="hljs-keyword">new</span> (<span class="hljs-keyword">if</span> acc <span class="hljs-keyword">then</span> Access <span class="hljs-keyword">else</span> Index) idx]
2015-09-03 12:37:36 -04:00
val = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, val, defaultValue <span class="hljs-keyword">if</span> defaultValue
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> name?
message = isUnassignable name
obj.error message <span class="hljs-keyword">if</span> message
assigns.push <span class="hljs-keyword">new</span> Assign(obj, val, <span class="hljs-literal">null</span>, param: @param, subpattern: <span class="hljs-literal">yes</span>).compileToFragments o, LEVEL_LIST
assigns.push vvar <span class="hljs-keyword">unless</span> top <span class="hljs-keyword">or</span> @subpattern
fragments = @joinFragmentArrays assigns, <span class="hljs-string">', '</span>
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInBraces fragments</pre></div></div>
2013-03-18 01:06:33 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-117">
2013-03-18 01:06:33 -04:00
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-117">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-01-29 23:54:00 -05:00
more than once.</p>
</div>
2016-09-22 16:19:43 -04:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-118">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-118">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Disallow conditional assignment of undefined variables.</p>
</div>
2014-01-29 23:54:00 -05:00
<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>
2016-09-22 16:19:43 -04:00
left.base <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> ThisLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check left.base.value
@variable.error <span class="hljs-string">"the variable \"<span class="hljs-subst">#{left.base.value}</span>\" can't be assigned with <span class="hljs-subst">#{@context}</span> because it has not been declared before"</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">"?"</span> <span class="hljs-keyword">in</span> @context
2014-01-29 23:54:00 -05:00
o.isExistentialEquals = <span class="hljs-literal">true</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(left), right, type: <span class="hljs-string">'if'</span>).addElse(<span class="hljs-keyword">new</span> Assign(right, @value, <span class="hljs-string">'='</span>)).compileToFragments o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
fragments = <span class="hljs-keyword">new</span> Op(@context[...<span class="hljs-number">-1</span>], left, <span class="hljs-keyword">new</span> Assign(right, @value, <span class="hljs-string">'='</span>)).compileToFragments o
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInBraces fragments</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-119">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-119">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<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>
2016-09-22 16:19:43 -04:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-120">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-120">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Compile the assignment from an array splice literal, using JavaScripts
2014-01-29 23:54:00 -05:00
<code>Array#splice</code> method.</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileSplice: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
{range: {from, to, exclusive}} = @variable.properties.pop()
name = @variable.compile o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> from
2016-09-22 16:19:43 -04:00
[fromDecl, fromRef] = @cacheToCodeFragments from.cache o, LEVEL_OP
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
fromDecl = fromRef = <span class="hljs-string">'0'</span>
<span class="hljs-keyword">if</span> to
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> from?.isNumber() <span class="hljs-keyword">and</span> to.isNumber()
2014-01-29 23:54:00 -05:00
to = to.compile(o) - fromRef
to += <span class="hljs-number">1</span> <span class="hljs-keyword">unless</span> exclusive
<span class="hljs-keyword">else</span>
to = to.compile(o, LEVEL_ACCESS) + <span class="hljs-string">' - '</span> + fromRef
to += <span class="hljs-string">' + 1'</span> <span class="hljs-keyword">unless</span> exclusive
<span class="hljs-keyword">else</span>
to = <span class="hljs-string">"9e9"</span>
2016-09-22 16:19:43 -04:00
[valDef, valRef] = @value.cache o, LEVEL_LIST
answer = [].concat @makeCode(<span class="hljs-string">"[].splice.apply(<span class="hljs-subst">#{name}</span>, [<span class="hljs-subst">#{fromDecl}</span>, <span class="hljs-subst">#{to}</span>].concat("</span>), valDef, @makeCode(<span class="hljs-string">")), "</span>), valRef
<span class="hljs-keyword">if</span> o.level &gt; LEVEL_TOP <span class="hljs-keyword">then</span> @wrapInBraces answer <span class="hljs-keyword">else</span> answer</pre></div></div>
2014-01-29 23:54:00 -05:00
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-121">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-121">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="code">Code</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-122">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-122">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A function definition. This is the only node that creates a new Scope.
2010-12-24 14:02:10 -05:00
When for the purposes of walking the contents of a function body, the Code
2016-09-22 16:19:43 -04:00
has no <em>children</em> theyre within the inner scope.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Code = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(params, body, tag)</span> -&gt;</span>
@params = params <span class="hljs-keyword">or</span> []
@body = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block
@bound = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'boundfunc'</span>
@isGenerator = !!@body.contains (node) -&gt;
(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
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'params'</span>, <span class="hljs-string">'body'</span>]
2016-09-22 16:19:43 -04:00
isStatement: <span class="hljs-function">-&gt;</span> !!@ctor
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
jumps: NO
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
makeScope: <span class="hljs-function"><span class="hljs-params">(parentScope)</span> -&gt;</span> <span class="hljs-keyword">new</span> Scope parentScope, @body, <span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-123">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-123">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Compilation creates a new scope unless explicitly asked to share with the
2010-12-24 14:02:10 -05:00
outer scope. Handles splat parameters in the parameter list by peeking at
2011-08-04 23:17:23 -04:00
the JavaScript <code>arguments</code> object. If the function is bound with the <code>=&gt;</code>
2010-12-24 14:02:10 -05:00
arrow, generates a wrapper that saves the current value of <code>this</code> through
2014-01-29 23:54:00 -05:00
a closure.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @bound <span class="hljs-keyword">and</span> o.scope.method?.bound
@context = o.scope.method.context</pre></div></div>
2014-01-29 23:54:00 -05:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-124">
2014-01-29 23:54:00 -05:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-124">&#182;</a>
2014-01-29 23:54:00 -05:00
</div>
<p>Handle bound functions early.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> @bound <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @context
@context = <span class="hljs-string">'_this'</span>
wrapper = <span class="hljs-keyword">new</span> Code [<span class="hljs-keyword">new</span> Param <span class="hljs-keyword">new</span> IdentifierLiteral @context], <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">this</span>]
boundfunc = <span class="hljs-keyword">new</span> Call(wrapper, [<span class="hljs-keyword">new</span> ThisLiteral])
boundfunc.updateLocationDataIfMissing @locationData
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> boundfunc.compileNode(o)
2016-09-22 16:19:43 -04:00
o.scope = del(o, <span class="hljs-string">'classScope'</span>) <span class="hljs-keyword">or</span> @makeScope o.scope
2014-01-29 23:54:00 -05:00
o.scope.shared = del(o, <span class="hljs-string">'sharedScope'</span>)
2013-03-18 01:06:33 -04:00
o.indent += TAB
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">delete</span> o.bare
<span class="hljs-keyword">delete</span> o.isExistentialEquals
2013-03-18 01:06:33 -04:00
params = []
exprs = []
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params <span class="hljs-keyword">when</span> param <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
2014-01-29 23:54:00 -05:00
o.scope.parameter param.asReference o
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params <span class="hljs-keyword">when</span> param.splat <span class="hljs-keyword">or</span> param <span class="hljs-keyword">instanceof</span> Expansion
<span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> @params <span class="hljs-keyword">when</span> p <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion <span class="hljs-keyword">and</span> p.name.value
2015-01-29 12:20:46 -05:00
o.scope.add p.name.value, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span>
2016-09-22 16:19:43 -04:00
splats = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Arr(p.asReference o <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> @params)),
<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral <span class="hljs-string">'arguments'</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">break</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> @params
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> param.isComplex()
2013-03-18 01:06:33 -04:00
val = ref = param.asReference o
2014-01-29 23:54:00 -05:00
val = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, ref, param.value <span class="hljs-keyword">if</span> param.value
2016-09-22 16:19:43 -04:00
exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), val, <span class="hljs-string">'='</span>, param: <span class="hljs-literal">yes</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
ref = param
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> param.value
lit = <span class="hljs-keyword">new</span> Literal ref.name.value + <span class="hljs-string">' == null'</span>
val = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), param.value, <span class="hljs-string">'='</span>
exprs.push <span class="hljs-keyword">new</span> If lit, val
params.push ref <span class="hljs-keyword">unless</span> splats
2016-09-22 16:19:43 -04:00
wasEmpty = @body.isEmpty()
2014-01-29 23:54:00 -05:00
exprs.unshift splats <span class="hljs-keyword">if</span> splats
2016-09-22 16:19:43 -04:00
@body.expressions.unshift exprs... <span class="hljs-keyword">if</span> exprs.length
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> p, i <span class="hljs-keyword">in</span> params
2013-03-18 01:06:33 -04:00
params[i] = p.compileToFragments o
o.scope.parameter fragmentsToText params[i]
uniqs = []
2016-09-22 16:19:43 -04:00
@eachParamName (name, node) -&gt;
2015-01-29 12:20:46 -05:00
node.error <span class="hljs-string">"multiple parameters named <span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> uniqs
2013-03-18 01:06:33 -04:00
uniqs.push name
2016-09-22 16:19:43 -04:00
@body.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> @noReturn
2015-01-29 12:20:46 -05:00
code = <span class="hljs-string">'function'</span>
2016-09-22 16:19:43 -04:00
code += <span class="hljs-string">'*'</span> <span class="hljs-keyword">if</span> @isGenerator
code += <span class="hljs-string">' '</span> + @name <span class="hljs-keyword">if</span> @ctor
2015-01-29 12:20:46 -05:00
code += <span class="hljs-string">'('</span>
2016-09-22 16:19:43 -04:00
answer = [@makeCode(code)]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> p, i <span class="hljs-keyword">in</span> params
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push @makeCode <span class="hljs-string">", "</span>
2013-03-18 01:06:33 -04:00
answer.push p...
2016-09-22 16:19:43 -04:00
answer.push @makeCode <span class="hljs-string">') {'</span>
answer = answer.concat(@makeCode(<span class="hljs-string">"\n"</span>), @body.compileWithDeclarations(o), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>)) <span class="hljs-keyword">unless</span> @body.isEmpty()
answer.push @makeCode <span class="hljs-string">'}'</span>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> [@makeCode(@tab), answer...] <span class="hljs-keyword">if</span> @ctor
<span class="hljs-keyword">if</span> @front <span class="hljs-keyword">or</span> (o.level &gt;= LEVEL_ACCESS) <span class="hljs-keyword">then</span> @wrapInBraces answer <span class="hljs-keyword">else</span> answer
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-125">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-125">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries
2014-01-29 23:54:00 -05:00
unless <code>crossScope</code> is <code>true</code>.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> traverseChildren: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">super</span>(crossScope, func) <span class="hljs-keyword">if</span> crossScope</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-126">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-126">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="param">Param</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-127">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-127">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>A parameter in a function definition. Beyond a typical JavaScript parameter,
2010-12-24 14:02:10 -05:00
these parameters can also attach themselves to the context of the function,
2014-01-29 23:54:00 -05:00
as well as be a splat, gathering up a group of parameters into an array.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Param = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Param</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@name, @value, @splat)</span> -&gt;</span>
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
2015-09-03 12:37:36 -04:00
token.error <span class="hljs-string">"unexpected <span class="hljs-subst">#{token.value}</span>"</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'name'</span>, <span class="hljs-string">'value'</span>]
2010-08-03 00:06:34 -04:00
2016-09-22 16:19:43 -04:00
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragments o, LEVEL_LIST
2010-08-03 00:06:34 -04:00
2016-09-22 16:19:43 -04:00
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
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span>
2015-02-03 11:31:43 -05:00
name = node.properties[<span class="hljs-number">0</span>].name.value
2016-09-22 16:19:43 -04:00
name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> JS_FORBIDDEN
node = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable name
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.isComplex()
2016-09-22 16:19:43 -04:00
node = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'arg'</span>
2014-01-29 23:54:00 -05:00
node = <span class="hljs-keyword">new</span> Value node
2016-09-22 16:19:43 -04:00
node = <span class="hljs-keyword">new</span> Splat node <span class="hljs-keyword">if</span> @splat
node.updateLocationDataIfMissing @locationData
@reference = node
2010-08-03 00:06:34 -04:00
2016-09-22 16:19:43 -04:00
isComplex: <span class="hljs-function">-&gt;</span>
@name.isComplex()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-128">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-128">&#182;</a>
2013-03-18 01:06:33 -04:00
</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
2014-01-29 23:54:00 -05:00
to that name.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> eachName: <span class="hljs-function"><span class="hljs-params">(iterator, name = @name)</span>-&gt;</span>
<span class="hljs-function"> <span class="hljs-title">atParam</span> = <span class="hljs-params">(obj)</span> -&gt;</span> iterator <span class="hljs-string">"@<span class="hljs-subst">#{obj.properties[<span class="hljs-number">0</span>].name.value}</span>"</span>, obj</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-129">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-129">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-04-10 14:57:45 -04:00
<li>simple literals <code>foo</code></li>
</ul>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> iterator name.value, name <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Literal</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-130">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-130">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-04-10 14:57:45 -04:00
<li>at-params <code>@foo</code></li>
</ul>
</div>
2014-01-29 23:54:00 -05:00
<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
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> name.objects ? []</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-131">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-131">&#182;</a>
2015-09-03 12:37:36 -04:00
</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>
2016-09-22 16:19:43 -04:00
<li id="section-132">
2015-09-03 12:37:36 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-132">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-04-10 14:57:45 -04:00
<li>assignments within destructured parameters <code>{foo:bar}</code></li>
</ul>
</div>
2016-09-22 16:19:43 -04:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-133">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-133">&#182;</a>
</div>
<p>… possibly with a default value</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.value <span class="hljs-keyword">instanceof</span> Assign
obj = obj.value
@eachName iterator, obj.value.unwrap()</pre></div></div>
</li>
<li id="section-134">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-134">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-05-14 14:45:20 -04:00
<li>splats within destructured parameters <code>[xs...]</code></li>
</ul>
</div>
2014-01-29 23:54:00 -05:00
<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
2013-03-18 01:06:33 -04:00
node = obj.name.unwrap()
iterator node.value, node
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Value</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-135">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-135">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-04-10 14:57:45 -04:00
<li>destructured parameters within destructured parameters <code>[{a}]</code></li>
</ul>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.isArray() <span class="hljs-keyword">or</span> obj.isObject()
2016-09-22 16:19:43 -04:00
@eachName iterator, obj.base</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-136">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-136">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<ul>
2012-04-10 14:57:45 -04:00
<li>at-params within destructured parameters <code>{@foo}</code></li>
</ul>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span>
2013-03-18 01:06:33 -04:00
atParam obj</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-137">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-137">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<ul>
<li>simple destructured parameters {foo}</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> iterator obj.base.value, obj.base
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
obj.error <span class="hljs-string">"illegal parameter <span class="hljs-subst">#{obj.compile()}</span>"</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-138">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-138">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<h3 id="splat">Splat</h3>
</div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-139">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-139">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>A splat, either as a parameter to a function, an argument to a call,
2014-01-29 23:54:00 -05:00
or as part of a destructuring assignment.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Splat = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Splat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'name'</span>]
2016-09-22 16:19:43 -04:00
isAssignable: YES
2016-09-22 16:19:43 -04:00
constructor: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@name = <span class="hljs-keyword">if</span> name.compile <span class="hljs-keyword">then</span> name <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Literal name
2016-09-22 16:19:43 -04:00
assigns: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
@name.assigns name
2016-09-22 16:19:43 -04:00
compileToFragments: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@name.compileToFragments o
2012-04-10 14:57:45 -04:00
2016-09-22 16:19:43 -04:00
unwrap: <span class="hljs-function">-&gt;</span> @name</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-140">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-140">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Utility function that converts an arbitrary number of elements, mixed with
2014-01-29 23:54:00 -05:00
splats, to a proper array.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> @compileSplattedArray: <span class="hljs-function"><span class="hljs-params">(o, list, apply)</span> -&gt;</span>
index = <span class="hljs-number">-1</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">while</span> (node = list[++index]) <span class="hljs-keyword">and</span> node <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Splat
<span class="hljs-keyword">return</span> [] <span class="hljs-keyword">if</span> index &gt;= list.length
<span class="hljs-keyword">if</span> list.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
node = list[<span class="hljs-number">0</span>]
2013-03-18 01:06:33 -04:00
fragments = node.compileToFragments o, LEVEL_LIST
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> apply
2015-01-29 12:20:46 -05:00
<span class="hljs-keyword">return</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call("</span>), fragments, node.makeCode(<span class="hljs-string">")"</span>)
2013-03-18 01:06:33 -04:00
args = list[index..]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> args
2013-03-18 01:06:33 -04:00
compiledNode = node.compileToFragments o, LEVEL_LIST
2014-01-29 23:54:00 -05:00
args[i] = <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Splat
2015-01-29 12:20:46 -05:00
<span class="hljs-keyword">then</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call("</span>), compiledNode, node.makeCode(<span class="hljs-string">")"</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span> [].concat node.makeCode(<span class="hljs-string">"["</span>), compiledNode, node.makeCode(<span class="hljs-string">"]"</span>)
<span class="hljs-keyword">if</span> index <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
node = list[<span class="hljs-number">0</span>]
concatPart = (node.joinFragmentArrays args[<span class="hljs-number">1.</span>.], <span class="hljs-string">', '</span>)
<span class="hljs-keyword">return</span> args[<span class="hljs-number">0</span>].concat node.makeCode(<span class="hljs-string">".concat("</span>), concatPart, node.makeCode(<span class="hljs-string">")"</span>)
base = (node.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> list[...index])
base = list[<span class="hljs-number">0</span>].joinFragmentArrays base, <span class="hljs-string">', '</span>
concatPart = list[index].joinFragmentArrays args, <span class="hljs-string">', '</span>
2015-02-18 15:43:33 -05:00
[..., last] = list
[].concat list[<span class="hljs-number">0</span>].makeCode(<span class="hljs-string">"["</span>), base, list[index].makeCode(<span class="hljs-string">"].concat("</span>), concatPart, last.makeCode(<span class="hljs-string">")"</span>)</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-141">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-141">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="expansion">Expansion</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-142">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-142">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>Used to skip values inside an array destructuring (pattern matching) or
2014-01-29 23:54:00 -05:00
parameter list.</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Expansion = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expansion</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
isComplex: NO
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@error <span class="hljs-string">'Expansion must be used inside a destructuring assignment or parameter list'</span>
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
asReference: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
eachName: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -&gt;</span></pre></div></div>
2014-01-29 23:54:00 -05:00
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-143">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-143">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="while">While</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-144">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-144">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
2010-12-24 14:02:10 -05:00
it, all other loops can be manufactured. Useful in cases where you need more
2014-01-29 23:54:00 -05:00
flexibility or more speed than a comprehension can provide.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.While = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">While</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(condition, options)</span> -&gt;</span>
@condition = <span class="hljs-keyword">if</span> options?.invert <span class="hljs-keyword">then</span> condition.invert() <span class="hljs-keyword">else</span> condition
@guard = options?.guard
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'body'</span>]
2016-09-22 16:19:43 -04:00
isStatement: YES
2016-09-22 16:19:43 -04:00
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> res
<span class="hljs-keyword">super</span>
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@returns = <span class="hljs-keyword">not</span> @jumps loop: <span class="hljs-literal">yes</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2010-03-23 00:18:50 -04:00
2016-09-22 16:19:43 -04:00
addBody: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
jumps: <span class="hljs-function">-&gt;</span>
{expressions} = @body
2014-01-29 23:54:00 -05:00
<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
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = node.jumps loop: <span class="hljs-literal">yes</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-literal">no</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-145">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-145">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
2016-09-22 16:19:43 -04:00
<em>while</em> can be used as a part of a larger expression while loops may
2014-01-29 23:54:00 -05:00
return an array containing the computed result of each iteration.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
o.indent += TAB
2014-01-29 23:54:00 -05:00
set = <span class="hljs-string">''</span>
{body} = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">if</span> body.isEmpty()
2016-09-22 16:19:43 -04:00
body = @makeCode <span class="hljs-string">''</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @returns
2014-01-29 23:54:00 -05:00
body.makeReturn rvar = o.scope.freeVariable <span class="hljs-string">'results'</span>
2016-09-22 16:19:43 -04:00
set = <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span>
<span class="hljs-keyword">if</span> @guard
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> body.expressions.length &gt; <span class="hljs-number">1</span>
2016-09-22 16:19:43 -04:00
body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens @guard).invert(), <span class="hljs-keyword">new</span> StatementLiteral <span class="hljs-string">"continue"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
body = Block.wrap [<span class="hljs-keyword">new</span> If @guard, body] <span class="hljs-keyword">if</span> @guard
body = [].concat @makeCode(<span class="hljs-string">"\n"</span>), (body.compileToFragments o, LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>"</span>)
answer = [].concat @makeCode(set + @tab + <span class="hljs-string">"while ("</span>), @condition.compileToFragments(o, LEVEL_PAREN),
@makeCode(<span class="hljs-string">") {"</span>), body, @makeCode(<span class="hljs-string">"}"</span>)
<span class="hljs-keyword">if</span> @returns
answer.push @makeCode <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;"</span>
2013-03-18 01:06:33 -04:00
answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-146">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-146">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="op">Op</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-147">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-147">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>Simple Arithmetic and logical operations. Performs some conversion from
2014-01-29 23:54:00 -05:00
CoffeeScript operations into their JavaScript equivalents.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Op = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Op</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(op, first, second, flip )</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> In first, second <span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'in'</span>
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'do'</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> @generateDo first
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span>
<span class="hljs-keyword">return</span> first.newInstance() <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.<span class="hljs-keyword">do</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.isNew
first = <span class="hljs-keyword">new</span> Parens first <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> first.bound <span class="hljs-keyword">or</span> first.<span class="hljs-keyword">do</span>
2016-09-22 16:19:43 -04:00
@operator = CONVERSIONS[op] <span class="hljs-keyword">or</span> op
@first = first
@second = second
@flip = !!flip
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-148">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-148">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>The map of conversions from CoffeeScript to JavaScript symbols.</p>
</div>
2013-03-18 01:06:33 -04:00
<div class="content"><div class='highlight'><pre> CONVERSIONS =
2015-01-29 12:20:46 -05:00
<span class="hljs-string">'=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'!='</span>: <span class="hljs-string">'!=='</span>
<span class="hljs-string">'of'</span>: <span class="hljs-string">'in'</span>
<span class="hljs-string">'yieldfrom'</span>: <span class="hljs-string">'yield*'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-149">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-149">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>The map of invertible operators.</p>
</div>
2013-03-18 01:06:33 -04:00
<div class="content"><div class='highlight'><pre> INVERSIONS =
2014-01-29 23:54:00 -05:00
<span class="hljs-string">'!=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'==='</span>: <span class="hljs-string">'!=='</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'first'</span>, <span class="hljs-string">'second'</span>]
2016-09-22 16:19:43 -04:00
isNumber: <span class="hljs-function">-&gt;</span>
@isUnary() <span class="hljs-keyword">and</span> @operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>] <span class="hljs-keyword">and</span>
@first <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> @first.isNumber()
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
isYield: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>]
2015-01-29 12:20:46 -05:00
2016-09-22 16:19:43 -04:00
isUnary: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @second
2015-02-18 15:43:33 -05:00
2016-09-22 16:19:43 -04:00
isComplex: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">not</span> @isNumber()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-150">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-150">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Am I capable of
2014-01-29 23:54:00 -05:00
<a href="http://docs.python.org/reference/expressions.html#notin">Python-style comparison chaining</a>?</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> isChainable: <span class="hljs-function">-&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'&lt;'</span>, <span class="hljs-string">'&gt;'</span>, <span class="hljs-string">'&gt;='</span>, <span class="hljs-string">'&lt;='</span>, <span class="hljs-string">'==='</span>, <span class="hljs-string">'!=='</span>]
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
invert: <span class="hljs-function">-&gt;</span>
<span class="hljs-keyword">if</span> @isChainable() <span class="hljs-keyword">and</span> @first.isChainable()
2014-01-29 23:54:00 -05:00
allInvertable = <span class="hljs-literal">yes</span>
curr = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator
allInvertable <span class="hljs-keyword">and</span>= (curr.operator <span class="hljs-keyword">of</span> INVERSIONS)
2013-03-18 01:06:33 -04:00
curr = curr.first
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert() <span class="hljs-keyword">unless</span> allInvertable
curr = <span class="hljs-keyword">this</span>
<span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator
2013-03-18 01:06:33 -04:00
curr.invert = !curr.invert
curr.operator = INVERSIONS[curr.operator]
curr = curr.first
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
<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()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @second
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert()
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">and</span> (fst = @first.unwrap()) <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span>
2014-01-29 23:54:00 -05:00
fst.operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'!'</span>, <span class="hljs-string">'in'</span>, <span class="hljs-string">'instanceof'</span>]
2013-03-18 01:06:33 -04:00
fst
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
unfoldSoak: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'++'</span>, <span class="hljs-string">'--'</span>, <span class="hljs-string">'delete'</span>] <span class="hljs-keyword">and</span> unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'first'</span>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
generateDo: <span class="hljs-function"><span class="hljs-params">(exp)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
passedParams = []
2014-01-29 23:54:00 -05:00
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
2013-03-18 01:06:33 -04:00
ref
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
exp
2014-01-29 23:54:00 -05:00
<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
2013-03-18 01:06:33 -04:00
passedParams.push param.value
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">delete</span> param.value
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
passedParams.push param
2014-01-29 23:54:00 -05:00
call = <span class="hljs-keyword">new</span> Call exp, passedParams
call.<span class="hljs-keyword">do</span> = <span class="hljs-literal">yes</span>
2013-03-18 01:06:33 -04:00
call
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
isChain = @isChainable() <span class="hljs-keyword">and</span> @first.isChainable()</pre></div></div>
2013-03-18 01:06:33 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-151">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-151">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>In chains, theres no need to wrap bare obj literals in parens,
2014-01-29 23:54:00 -05:00
as the chained expression is wrapped.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> @first.front = @front <span class="hljs-keyword">unless</span> isChain
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">is</span> <span class="hljs-string">'delete'</span> <span class="hljs-keyword">and</span> o.scope.check(@first.unwrapAll().value)
@error <span class="hljs-string">'delete operand may not be argument or var'</span>
<span class="hljs-keyword">if</span> @operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>]
message = isUnassignable @first.unwrapAll().value
@first.error message <span class="hljs-keyword">if</span> message
<span class="hljs-keyword">return</span> @compileYield o <span class="hljs-keyword">if</span> @isYield()
<span class="hljs-keyword">return</span> @compileUnary o <span class="hljs-keyword">if</span> @isUnary()
<span class="hljs-keyword">return</span> @compileChain o <span class="hljs-keyword">if</span> isChain
<span class="hljs-keyword">switch</span> @operator
<span class="hljs-keyword">when</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">then</span> @compileExistence o
<span class="hljs-keyword">when</span> <span class="hljs-string">'**'</span> <span class="hljs-keyword">then</span> @compilePower o
<span class="hljs-keyword">when</span> <span class="hljs-string">'//'</span> <span class="hljs-keyword">then</span> @compileFloorDivision o
<span class="hljs-keyword">when</span> <span class="hljs-string">'%%'</span> <span class="hljs-keyword">then</span> @compileModulo o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
lhs = @first.compileToFragments o, LEVEL_OP
rhs = @second.compileToFragments o, LEVEL_OP
answer = [].concat lhs, @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{@operator}</span> "</span>), rhs
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_OP <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> @wrapInBraces answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-152">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-152">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Mimic Pythons chained comparisons when multiple comparison operators are
2014-01-29 23:54:00 -05:00
used sequentially. For example:</p>
2014-08-23 10:08:39 -04:00
<pre><code>bin/coffee -e <span class="hljs-string">'console.log 50 &lt; 65 &gt; 10'</span>
<span class="hljs-literal">true</span>
2014-01-29 23:54:00 -05:00
</code></pre>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileChain: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[@first.second, shared] = @first.second.cache o
fst = @first.compileToFragments o, LEVEL_OP
fragments = fst.concat @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @invert <span class="hljs-keyword">then</span> <span class="hljs-string">'&amp;&amp;'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'||'</span>}</span> "</span>),
(shared.compileToFragments o), @makeCode(<span class="hljs-string">" <span class="hljs-subst">#{@operator}</span> "</span>), (@second.compileToFragments o, LEVEL_OP)
@wrapInBraces fragments</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-153">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-153">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Keep reference to the left expression, unless this an existential assignment</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileExistence: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">if</span> @first.isComplex()
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'ref'</span>
fst = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign ref, @first
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
fst = @first
2013-03-18 01:06:33 -04:00
ref = fst
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(fst), ref, type: <span class="hljs-string">'if'</span>).addElse(@second).compileToFragments o</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-154">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-154">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Compile a unary <strong>Op</strong>.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileUnary: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
parts = []
2016-09-22 16:19:43 -04:00
op = @operator
parts.push [@makeCode op]
<span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Existence
@first.negated = <span class="hljs-keyword">not</span> @first.negated
<span class="hljs-keyword">return</span> @first.compileToFragments o
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_ACCESS
<span class="hljs-keyword">return</span> (<span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">this</span>).compileToFragments o
plusMinus = op <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>]
2016-09-22 16:19:43 -04:00
parts.push [@makeCode(<span class="hljs-string">' '</span>)] <span class="hljs-keyword">if</span> op <span class="hljs-keyword">in</span> [<span class="hljs-string">'new'</span>, <span class="hljs-string">'typeof'</span>, <span class="hljs-string">'delete'</span>] <span class="hljs-keyword">or</span>
plusMinus <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> @first.operator <span class="hljs-keyword">is</span> op
<span class="hljs-keyword">if</span> (plusMinus <span class="hljs-keyword">and</span> @first <span class="hljs-keyword">instanceof</span> Op) <span class="hljs-keyword">or</span> (op <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span> <span class="hljs-keyword">and</span> @first.isStatement o)
@first = <span class="hljs-keyword">new</span> Parens @first
parts.push @first.compileToFragments o, LEVEL_OP
parts.reverse() <span class="hljs-keyword">if</span> @flip
@joinFragmentArrays parts, <span class="hljs-string">''</span>
compileYield: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2015-01-29 12:20:46 -05:00
parts = []
2016-09-22 16:19:43 -04:00
op = @operator
<span class="hljs-keyword">unless</span> o.scope.parent?
@error <span class="hljs-string">'yield can only occur inside functions'</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">'expression'</span> <span class="hljs-keyword">in</span> Object.keys(@first) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (@first <span class="hljs-keyword">instanceof</span> Throw)
parts.push @first.expression.compileToFragments o, LEVEL_OP <span class="hljs-keyword">if</span> @first.expression?
2015-01-29 12:20:46 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
parts.push [@makeCode <span class="hljs-string">"("</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
parts.push [@makeCode op]
parts.push [@makeCode <span class="hljs-string">" "</span>] <span class="hljs-keyword">if</span> @first.base?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">''</span>
parts.push @first.compileToFragments o, LEVEL_OP
parts.push [@makeCode <span class="hljs-string">")"</span>] <span class="hljs-keyword">if</span> o.level &gt;= LEVEL_PAREN
@joinFragmentArrays parts, <span class="hljs-string">''</span>
2015-01-29 12:20:46 -05:00
2016-09-22 16:19:43 -04:00
compilePower: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-155">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-155">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Make a Math.pow call</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> pow = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'pow'</span>]
<span class="hljs-keyword">new</span> Call(pow, [@first, @second]).compileToFragments o
2016-09-22 16:19:43 -04:00
compileFloorDivision: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
floor = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> IdentifierLiteral(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> PropertyName <span class="hljs-string">'floor'</span>]
div = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'/'</span>, @first, @second
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">new</span> Call(floor, [div]).compileToFragments o
2016-09-22 16:19:43 -04:00
compileModulo: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2015-01-29 12:20:46 -05:00
mod = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'modulo'</span>, o
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">new</span> Call(mod, [@first, @second]).compileToFragments o
2016-09-22 16:19:43 -04:00
toString: <span class="hljs-function"><span class="hljs-params">(idt)</span> -&gt;</span>
<span class="hljs-keyword">super</span> idt, @constructor.name + <span class="hljs-string">' '</span> + @operator</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-156">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-156">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="in">In</h3>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.In = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">In</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@object, @array)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'object'</span>, <span class="hljs-string">'array'</span>]
2016-09-22 16:19:43 -04:00
invert: NEGATE
2010-08-04 23:14:34 -04:00
2016-09-22 16:19:43 -04:00
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
2014-01-29 23:54:00 -05:00
hasSplat = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">break</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-157">
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-157">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p><code>compileOrTest</code> only if we have an array literal with no splats</p>
2013-06-02 01:37:45 -04:00
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> @compileOrTest o <span class="hljs-keyword">unless</span> hasSplat
@compileLoopTest o
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
compileOrTest: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[sub, ref] = @object.cache o, LEVEL_OP
[cmp, cnj] = <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> [<span class="hljs-string">' !== '</span>, <span class="hljs-string">' &amp;&amp; '</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">' === '</span>, <span class="hljs-string">' || '</span>]
2014-01-29 23:54:00 -05:00
tests = []
2016-09-22 16:19:43 -04:00
<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> @wrapInBraces tests
compileLoopTest: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[sub, ref] = @object.cache o, LEVEL_LIST
fragments = [].concat @makeCode(utility(<span class="hljs-string">'indexOf'</span>, o) + <span class="hljs-string">".call("</span>), @array.compileToFragments(o, LEVEL_LIST),
@makeCode(<span class="hljs-string">", "</span>), ref, @makeCode(<span class="hljs-string">") "</span> + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'&lt; 0'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'&gt;= 0'</span>)
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> fragmentsToText(sub) <span class="hljs-keyword">is</span> fragmentsToText(ref)
2016-09-22 16:19:43 -04:00
fragments = sub.concat @makeCode(<span class="hljs-string">', '</span>), fragments
<span class="hljs-keyword">if</span> o.level &lt; LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInBraces fragments
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
toString: <span class="hljs-function"><span class="hljs-params">(idt)</span> -&gt;</span>
<span class="hljs-keyword">super</span> idt, @constructor.name + <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span></pre></div></div>
2014-01-29 23:54:00 -05:00
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-158">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-158">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="try">Try</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-159">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-159">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A classic <em>try/catch/finally</em> block.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Try = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Try</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@attempt, @errorVariable, @recovery, @ensure)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'attempt'</span>, <span class="hljs-string">'recovery'</span>, <span class="hljs-string">'ensure'</span>]
2016-09-22 16:19:43 -04:00
isStatement: YES
2010-08-04 23:14:34 -04:00
2016-09-22 16:19:43 -04:00
jumps: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> @attempt.jumps(o) <span class="hljs-keyword">or</span> @recovery?.jumps(o)
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
@attempt = @attempt .makeReturn res <span class="hljs-keyword">if</span> @attempt
@recovery = @recovery.makeReturn res <span class="hljs-keyword">if</span> @recovery
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-160">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-160">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Compilation is more or less as you would expect the <em>finally</em> clause
2014-01-29 23:54:00 -05:00
is optional, the <em>catch</em> is not.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
o.indent += TAB
2016-09-22 16:19:43 -04:00
tryPart = @attempt.compileToFragments o, LEVEL_TOP
catchPart = <span class="hljs-keyword">if</span> @recovery
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">'error'</span>, reserve: <span class="hljs-literal">no</span>
placeholder = <span class="hljs-keyword">new</span> IdentifierLiteral generatedErrorVariableName
<span class="hljs-keyword">if</span> @errorVariable
message = isUnassignable @errorVariable.unwrapAll().value
@errorVariable.error message <span class="hljs-keyword">if</span> message
@recovery.unshift <span class="hljs-keyword">new</span> Assign @errorVariable, placeholder
[].concat @makeCode(<span class="hljs-string">" catch ("</span>), placeholder.compileToFragments(o), @makeCode(<span class="hljs-string">") {\n"</span>),
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
<span class="hljs-keyword">else</span> <span class="hljs-keyword">unless</span> @ensure <span class="hljs-keyword">or</span> @recovery
generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">'error'</span>, reserve: <span class="hljs-literal">no</span>
[@makeCode(<span class="hljs-string">" catch (<span class="hljs-subst">#{generatedErrorVariableName}</span>) {}"</span>)]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2013-03-18 01:06:33 -04:00
[]
2012-04-10 14:57:45 -04:00
2016-09-22 16:19:43 -04:00
ensurePart = <span class="hljs-keyword">if</span> @ensure <span class="hljs-keyword">then</span> ([].concat @makeCode(<span class="hljs-string">" finally {\n"</span>), @ensure.compileToFragments(o, LEVEL_TOP),
@makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)) <span class="hljs-keyword">else</span> []
2012-04-10 14:57:45 -04:00
2016-09-22 16:19:43 -04:00
[].concat @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>try {\n"</span>),
2013-03-18 01:06:33 -04:00
tryPart,
2016-09-22 16:19:43 -04:00
@makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>), catchPart, ensurePart</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-161">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-161">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="throw">Throw</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-162">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-162">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>Simple node to throw an exception.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Throw = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Throw</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'expression'</span>]
2016-09-22 16:19:43 -04:00
isStatement: YES
jumps: NO</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-163">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-163">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>A <strong>Throw</strong> is already a return, of sorts…</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> makeReturn: THIS
2013-06-02 01:37:45 -04:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[].concat @makeCode(@tab + <span class="hljs-string">"throw "</span>), @expression.compileToFragments(o), @makeCode(<span class="hljs-string">";"</span>)</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-164">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-164">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="existence">Existence</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-165">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-165">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
2016-09-22 16:19:43 -04:00
<p>Checks a variable for existence not <em>null</em> and not <em>undefined</em>. This is
2010-12-24 14:02:10 -05:00
similar to <code>.nil?</code> in Ruby, and avoids having to consult a JavaScript truth
2014-01-29 23:54:00 -05:00
table.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Existence = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Existence</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@expression)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'expression'</span>]
2016-09-22 16:19:43 -04:00
invert: NEGATE
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
@expression.front = @front
code = @expression.compile o, LEVEL_OP
<span class="hljs-keyword">if</span> @expression.unwrap() <span class="hljs-keyword">instanceof</span> IdentifierLiteral <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check code
[cmp, cnj] = <span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> [<span class="hljs-string">'==='</span>, <span class="hljs-string">'||'</span>] <span class="hljs-keyword">else</span> [<span class="hljs-string">'!=='</span>, <span class="hljs-string">'&amp;&amp;'</span>]
2014-01-29 23:54:00 -05:00
code = <span class="hljs-string">"typeof <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> \"undefined\" <span class="hljs-subst">#{cnj}</span> <span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{cmp}</span> null"</span>
<span class="hljs-keyword">else</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-166">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-166">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>do not use strict equality here; it will break existing code</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> code = <span class="hljs-string">"<span class="hljs-subst">#{code}</span> <span class="hljs-subst">#{<span class="hljs-keyword">if</span> @negated <span class="hljs-keyword">then</span> <span class="hljs-string">'=='</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'!='</span>}</span> null"</span>
[@makeCode(<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_COND <span class="hljs-keyword">then</span> code <span class="hljs-keyword">else</span> <span class="hljs-string">"(<span class="hljs-subst">#{code}</span>)"</span>)]</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-167">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-167">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="parens">Parens</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-168">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-168">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>An extra set of parentheses, specified explicitly in the source. At one time
2010-12-24 14:02:10 -05:00
we tried to clean up the results by detecting and removing redundant
2016-09-22 16:19:43 -04:00
parentheses, but no longer you can put in as many as you please.</p>
2014-01-29 23:54:00 -05:00
<p>Parentheses are a good way to force any statement to become an expression.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Parens = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parens</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@body)</span> -&gt;</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'body'</span>]
2010-03-23 00:18:50 -04:00
2016-09-22 16:19:43 -04:00
unwrap : <span class="hljs-function">-&gt;</span> @body
isComplex : <span class="hljs-function">-&gt;</span> @body.isComplex()
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
expr = @body.unwrap()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isAtomic()
2016-09-22 16:19:43 -04:00
expr.front = @front
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> expr.compileToFragments o
2013-03-18 01:06:33 -04:00
fragments = expr.compileToFragments o, LEVEL_PAREN
2014-01-29 23:54:00 -05:00
bare = o.level &lt; LEVEL_OP <span class="hljs-keyword">and</span> (expr <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">or</span> expr <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">or</span>
(expr <span class="hljs-keyword">instanceof</span> For <span class="hljs-keyword">and</span> expr.returns))
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> bare <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> @wrapInBraces fragments</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-169">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-169">&#182;</a>
</div>
<h3 id="stringwithinterpolations">StringWithInterpolations</h3>
</div>
</li>
<li id="section-170">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-170">&#182;</a>
</div>
<p>Strings with interpolations are in fact just a variation of <code>Parens</code> with
string concatenation inside.</p>
</div>
<div class="content"><div class='highlight'><pre>
exports.StringWithInterpolations = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringWithInterpolations</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Parens</span></span></pre></div></div>
</li>
<li id="section-171">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-171">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="for">For</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-172">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-172">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>CoffeeScripts replacement for the <em>for</em> loop is our array and object
2010-12-24 14:02:10 -05:00
comprehensions, that compile into <em>for</em> loops here. They also act as an
2014-01-29 23:54:00 -05:00
expression, able to return the result of each filtered iteration.</p>
2010-12-24 14:02:10 -05:00
<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,
2014-01-29 23:54:00 -05:00
you can map and filter in a single pass.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.For = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">For</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">While</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(body, source)</span> -&gt;</span>
{@source, @guard, @step, @name, @index} = source
@body = Block.wrap [body]
@own = !!source.own
@object = !!source.object
[@name, @index] = [@index, @name] <span class="hljs-keyword">if</span> @object
@index.error <span class="hljs-string">'index cannot be a pattern matching expression'</span> <span class="hljs-keyword">if</span> @index <span class="hljs-keyword">instanceof</span> Value
@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
@pattern = @name <span class="hljs-keyword">instanceof</span> Value
@index.error <span class="hljs-string">'indexes do not apply to range loops'</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @index
@name.error <span class="hljs-string">'cannot pattern match over range loops'</span> <span class="hljs-keyword">if</span> @range <span class="hljs-keyword">and</span> @pattern
@name.error <span class="hljs-string">'cannot use own with for-in'</span> <span class="hljs-keyword">if</span> @own <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @object
@returns = <span class="hljs-literal">false</span>
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'body'</span>, <span class="hljs-string">'source'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'step'</span>]</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-173">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-173">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
2010-12-24 14:02:10 -05:00
loop, filtering, stepping, and result saving for array, object, and range
comprehensions. Some of the generated code can be shared in common, and
2014-01-29 23:54:00 -05:00
some cannot.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
body = Block.wrap [@body]
2015-02-18 15:43:33 -05:00
[..., last] = body.expressions
2016-09-22 16:19:43 -04:00
@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
2015-02-18 15:43:33 -05:00
scope = o.scope
2016-09-22 16:19:43 -04:00
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
2014-01-29 23:54:00 -05:00
scope.find(index) <span class="hljs-keyword">if</span> index
2016-09-22 16:19:43 -04:00
rvar = scope.freeVariable <span class="hljs-string">'results'</span> <span class="hljs-keyword">if</span> @returns
ivar = (@object <span class="hljs-keyword">and</span> index) <span class="hljs-keyword">or</span> scope.freeVariable <span class="hljs-string">'i'</span>, single: <span class="hljs-literal">true</span>
kvar = (@range <span class="hljs-keyword">and</span> name) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">or</span> ivar
2015-02-18 15:43:33 -05:00
kvarAssign = <span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> = "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
2016-09-22 16:19:43 -04:00
<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, isComplexOrAssignable
stepNum = Number stepVar <span class="hljs-keyword">if</span> @step.isNumber()
name = ivar <span class="hljs-keyword">if</span> @pattern
2015-02-18 15:43:33 -05:00
varPart = <span class="hljs-string">''</span>
guardPart = <span class="hljs-string">''</span>
defPart = <span class="hljs-string">''</span>
2016-09-22 16:19:43 -04:00
idt1 = @tab + TAB
<span class="hljs-keyword">if</span> @range
2015-02-18 15:43:33 -05:00
forPartFragments = source.compileToFragments merge o,
2016-09-22 16:19:43 -04:00
{index: ivar, name, @step, isComplex: isComplexOrAssignable}
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
svar = @source.compile o, LEVEL_LIST
<span class="hljs-keyword">if</span> (name <span class="hljs-keyword">or</span> @own) <span class="hljs-keyword">and</span> @source.unwrap() <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> IdentifierLiteral
defPart += <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{ref = scope.freeVariable <span class="hljs-string">'ref'</span>}</span> = <span class="hljs-subst">#{svar}</span>;\n"</span>
2013-03-18 01:06:33 -04:00
svar = ref
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @pattern
2014-01-29 23:54:00 -05:00
namePart = <span class="hljs-string">"<span class="hljs-subst">#{name}</span> = <span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @object
defPart += <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{step}</span>;\n"</span> <span class="hljs-keyword">if</span> step <span class="hljs-keyword">isnt</span> stepVar
down = stepNum &lt; <span class="hljs-number">0</span>
lvar = scope.freeVariable <span class="hljs-string">'len'</span> <span class="hljs-keyword">unless</span> @step <span class="hljs-keyword">and</span> stepNum? <span class="hljs-keyword">and</span> down
2014-01-29 23:54:00 -05:00
declare = <span class="hljs-string">"<span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{ivar}</span> = 0, <span class="hljs-subst">#{lvar}</span> = <span class="hljs-subst">#{svar}</span>.length"</span>
declareDown = <span class="hljs-string">"<span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{svar}</span>.length - 1"</span>
compare = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> &lt; <span class="hljs-subst">#{lvar}</span>"</span>
compareDown = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> &gt;= 0"</span>
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @step
<span class="hljs-keyword">if</span> stepNum?
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> down
2013-03-18 01:06:33 -04:00
compare = compareDown
declare = declareDown
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
compare = <span class="hljs-string">"<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? <span class="hljs-subst">#{compare}</span> : <span class="hljs-subst">#{compareDown}</span>"</span>
declare = <span class="hljs-string">"(<span class="hljs-subst">#{stepVar}</span> &gt; 0 ? (<span class="hljs-subst">#{declare}</span>) : <span class="hljs-subst">#{declareDown}</span>)"</span>
increment = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> += <span class="hljs-subst">#{stepVar}</span>"</span>
<span class="hljs-keyword">else</span>
increment = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"++<span class="hljs-subst">#{ivar}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>}</span>"</span>
2016-09-22 16:19:43 -04:00
forPartFragments = [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{declare}</span>; <span class="hljs-subst">#{compare}</span>; <span class="hljs-subst">#{kvarAssign}</span><span class="hljs-subst">#{increment}</span>"</span>)]
<span class="hljs-keyword">if</span> @returns
resultPart = <span class="hljs-string">"<span class="hljs-subst">#{@tab}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span>
returnResult = <span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>return <span class="hljs-subst">#{rvar}</span>;"</span>
2013-03-18 01:06:33 -04:00
body.makeReturn rvar
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @guard
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> body.expressions.length &gt; <span class="hljs-number">1</span>
2016-09-22 16:19:43 -04:00
body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens @guard).invert(), <span class="hljs-keyword">new</span> StatementLiteral <span class="hljs-string">"continue"</span>
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
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">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span>
defPartFragments = [].concat @makeCode(defPart), @pluckDirectCall(o, body)
2014-01-29 23:54:00 -05:00
varPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span><span class="hljs-subst">#{namePart}</span>;"</span> <span class="hljs-keyword">if</span> namePart
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @object
forPartFragments = [@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> in <span class="hljs-subst">#{svar}</span>"</span>)]
guardPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span>if (!<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(<span class="hljs-subst">#{svar}</span>, <span class="hljs-subst">#{kvar}</span>)) continue;"</span> <span class="hljs-keyword">if</span> @own
bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> bodyFragments <span class="hljs-keyword">and</span> (bodyFragments.length &gt; <span class="hljs-number">0</span>)
2016-09-22 16:19:43 -04:00
bodyFragments = [].concat @makeCode(<span class="hljs-string">"\n"</span>), bodyFragments, @makeCode(<span class="hljs-string">"\n"</span>)
[].concat defPartFragments, @makeCode(<span class="hljs-string">"<span class="hljs-subst">#{resultPart <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span><span class="hljs-subst">#{@tab}</span>for ("</span>),
forPartFragments, @makeCode(<span class="hljs-string">") {<span class="hljs-subst">#{guardPart}</span><span class="hljs-subst">#{varPart}</span>"</span>), bodyFragments,
@makeCode(<span class="hljs-string">"<span class="hljs-subst">#{@tab}</span>}<span class="hljs-subst">#{returnResult <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span>"</span>)
2014-01-29 23:54:00 -05:00
2016-09-22 16:19:43 -04:00
pluckDirectCall: <span class="hljs-function"><span class="hljs-params">(o, body)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
defs = []
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> expr, idx <span class="hljs-keyword">in</span> body.expressions
2013-03-18 01:06:33 -04:00
expr = expr.unwrapAll()
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> expr <span class="hljs-keyword">instanceof</span> Call
val = expr.variable?.unwrapAll()
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> (val <span class="hljs-keyword">instanceof</span> Code) <span class="hljs-keyword">or</span>
(val <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span>
val.base?.unwrapAll() <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span>
val.properties.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span>
val.properties[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">in</span> [<span class="hljs-string">'call'</span>, <span class="hljs-string">'apply'</span>])
fn = val.base?.unwrapAll() <span class="hljs-keyword">or</span> val
2016-09-22 16:19:43 -04:00
ref = <span class="hljs-keyword">new</span> IdentifierLiteral o.scope.freeVariable <span class="hljs-string">'fn'</span>
2014-01-29 23:54:00 -05:00
base = <span class="hljs-keyword">new</span> Value ref
<span class="hljs-keyword">if</span> val.base
2013-03-18 01:06:33 -04:00
[val.base, base] = [base, val]
2014-01-29 23:54:00 -05:00
body.expressions[idx] = <span class="hljs-keyword">new</span> Call base, expr.args
2016-09-22 16:19:43 -04:00
defs = defs.concat @makeCode(@tab), (<span class="hljs-keyword">new</span> Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), @makeCode(<span class="hljs-string">';\n'</span>)
2013-03-18 01:06:33 -04:00
defs</pre></div></div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-174">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-174">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="switch">Switch</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-175">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-175">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.Switch = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Switch</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@subject, @cases, @otherwise)</span> -&gt;</span>
2010-09-16 00:32:57 -04:00
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'subject'</span>, <span class="hljs-string">'cases'</span>, <span class="hljs-string">'otherwise'</span>]
2010-09-16 00:32:57 -04:00
2016-09-22 16:19:43 -04:00
isStatement: YES
2010-09-16 00:32:57 -04:00
2016-09-22 16:19:43 -04:00
jumps: <span class="hljs-function"><span class="hljs-params">(o = {block: <span class="hljs-literal">yes</span>})</span> -&gt;</span>
<span class="hljs-keyword">for</span> [conds, block] <span class="hljs-keyword">in</span> @cases
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = block.jumps o
2016-09-22 16:19:43 -04:00
@otherwise?.jumps o
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
pair[<span class="hljs-number">1</span>].makeReturn res <span class="hljs-keyword">for</span> pair <span class="hljs-keyword">in</span> @cases
@otherwise <span class="hljs-keyword">or</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'void 0'</span>] <span class="hljs-keyword">if</span> res
@otherwise?.makeReturn res
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2010-09-16 00:32:57 -04:00
2016-09-22 16:19:43 -04:00
compileNode: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2013-03-18 01:06:33 -04:00
idt1 = o.indent + TAB
idt2 = o.indent = idt1 + TAB
2016-09-22 16:19:43 -04:00
fragments = [].concat @makeCode(@tab + <span class="hljs-string">"switch ("</span>),
(<span class="hljs-keyword">if</span> @subject <span class="hljs-keyword">then</span> @subject.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">else</span> @makeCode <span class="hljs-string">"false"</span>),
@makeCode(<span class="hljs-string">") {\n"</span>)
<span class="hljs-keyword">for</span> [conditions, block], i <span class="hljs-keyword">in</span> @cases
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">for</span> cond <span class="hljs-keyword">in</span> flatten [conditions]
2016-09-22 16:19:43 -04:00
cond = cond.invert() <span class="hljs-keyword">unless</span> @subject
fragments = fragments.concat @makeCode(idt1 + <span class="hljs-string">"case "</span>), cond.compileToFragments(o, LEVEL_PAREN), @makeCode(<span class="hljs-string">":\n"</span>)
fragments = fragments.concat body, @makeCode(<span class="hljs-string">'\n'</span>) <span class="hljs-keyword">if</span> (body = block.compileToFragments o, LEVEL_TOP).length &gt; <span class="hljs-number">0</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> @cases.length - <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> @otherwise
expr = @lastNonComment block.expressions
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">or</span> (expr <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> expr.jumps() <span class="hljs-keyword">and</span> expr.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'debugger'</span>)
fragments.push cond.makeCode(idt2 + <span class="hljs-string">'break;\n'</span>)
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">if</span> @otherwise <span class="hljs-keyword">and</span> @otherwise.expressions.length
fragments.push @makeCode(idt1 + <span class="hljs-string">"default:\n"</span>), (@otherwise.compileToFragments o, LEVEL_TOP)..., @makeCode(<span class="hljs-string">"\n"</span>)
fragments.push @makeCode @tab + <span class="hljs-string">'}'</span>
2013-03-18 01:06:33 -04:00
fragments</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-176">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-176">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h3 id="if">If</h3>
2014-08-23 10:08:39 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-177">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-177">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
<p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
2014-01-29 23:54:00 -05:00
to the last line of each clause.</p>
2010-12-24 14:02:10 -05:00
<p>Single-expression <strong>Ifs</strong> are compiled into conditional operators if possible,
2014-08-23 10:08:39 -04:00
because ternaries are already proper expressions, and dont need conversion.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre>exports.If = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">If</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(condition, @body, options = {})</span> -&gt;</span>
@condition = <span class="hljs-keyword">if</span> options.type <span class="hljs-keyword">is</span> <span class="hljs-string">'unless'</span> <span class="hljs-keyword">then</span> condition.invert() <span class="hljs-keyword">else</span> condition
@elseBody = <span class="hljs-literal">null</span>
@isChain = <span class="hljs-literal">false</span>
{@soak} = options
2016-09-22 16:19:43 -04:00
children: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'body'</span>, <span class="hljs-string">'elseBody'</span>]
2016-09-22 16:19:43 -04:00
bodyNode: <span class="hljs-function">-&gt;</span> @body?.unwrap()
elseBodyNode: <span class="hljs-function">-&gt;</span> @elseBody?.unwrap()</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-178">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-178">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p>
</div>
2016-09-22 16:19:43 -04:00
<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
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
@isChain = elseBody <span class="hljs-keyword">instanceof</span> If
@elseBody = @ensureBlock elseBody
@elseBody.updateLocationDataIfMissing elseBody.locationData
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-179">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-179">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
2014-01-29 23:54:00 -05:00
to be a statement. Otherwise a conditional operator is safe.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> isStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span>
2016-09-22 16:19:43 -04:00
@bodyNode().isStatement(o) <span class="hljs-keyword">or</span> @elseBodyNode()?.isStatement(o)
2016-09-22 16:19:43 -04:00
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)
2010-12-24 14:02:10 -05:00
2016-09-22 16:19:43 -04:00
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
2010-03-23 00:18:50 -04:00
2016-09-22 16:19:43 -04:00
makeReturn: <span class="hljs-function"><span class="hljs-params">(res)</span> -&gt;</span>
@elseBody <span class="hljs-keyword">or</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'void 0'</span>] <span class="hljs-keyword">if</span> res
@body <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@body.makeReturn res]
@elseBody <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [@elseBody.makeReturn res]
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">this</span>
2010-05-04 23:31:28 -04:00
2016-09-22 16:19:43 -04:00
ensureBlock: <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-180">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-180">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
<p>Compile the <code>If</code> as a regular <em>if-else</em> statement. Flattened chains
2014-01-29 23:54:00 -05:00
force inner <em>else</em> bodies into statement form.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileStatement: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
child = del o, <span class="hljs-string">'chainChild'</span>
exeq = del o, <span class="hljs-string">'isExistentialEquals'</span>
2011-08-04 23:17:23 -04:00
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">if</span> exeq
2016-09-22 16:19:43 -04:00
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If(@condition.invert(), @elseBodyNode(), type: <span class="hljs-string">'if'</span>).compileToFragments o
2011-08-04 23:17:23 -04:00
2013-03-18 01:06:33 -04:00
indent = o.indent + TAB
2016-09-22 16:19:43 -04:00
cond = @condition.compileToFragments o, LEVEL_PAREN
body = @ensureBlock(@body).compileToFragments merge o, {indent}
ifPart = [].concat @makeCode(<span class="hljs-string">"if ("</span>), cond, @makeCode(<span class="hljs-string">") {\n"</span>), body, @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
ifPart.unshift @makeCode @tab <span class="hljs-keyword">unless</span> child
<span class="hljs-keyword">return</span> ifPart <span class="hljs-keyword">unless</span> @elseBody
answer = ifPart.concat @makeCode(<span class="hljs-string">' else '</span>)
<span class="hljs-keyword">if</span> @isChain
2014-01-29 23:54:00 -05:00
o.chainChild = <span class="hljs-literal">yes</span>
2016-09-22 16:19:43 -04:00
answer = answer.concat @elseBody.unwrap().compileToFragments o, LEVEL_TOP
2014-01-29 23:54:00 -05:00
<span class="hljs-keyword">else</span>
2016-09-22 16:19:43 -04:00
answer = answer.concat @makeCode(<span class="hljs-string">"{\n"</span>), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode(<span class="hljs-string">"\n<span class="hljs-subst">#{@tab}</span>}"</span>)
2013-03-18 01:06:33 -04:00
answer</pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-181">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-181">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Compile the <code>If</code> as a conditional operator.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> compileExpression: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
cond = @condition.compileToFragments o, LEVEL_COND
body = @bodyNode().compileToFragments o, LEVEL_LIST
alt = <span class="hljs-keyword">if</span> @elseBodyNode() <span class="hljs-keyword">then</span> @elseBodyNode().compileToFragments(o, LEVEL_LIST) <span class="hljs-keyword">else</span> [@makeCode(<span class="hljs-string">'void 0'</span>)]
fragments = cond.concat @makeCode(<span class="hljs-string">" ? "</span>), body, @makeCode(<span class="hljs-string">" : "</span>), alt
<span class="hljs-keyword">if</span> o.level &gt;= LEVEL_COND <span class="hljs-keyword">then</span> @wrapInBraces fragments <span class="hljs-keyword">else</span> fragments
2016-09-22 16:19:43 -04:00
unfoldSoak: <span class="hljs-function">-&gt;</span>
@soak <span class="hljs-keyword">and</span> <span class="hljs-keyword">this</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-182">
2013-03-18 01:06:33 -04:00
<div class="annotation">
2014-01-29 23:54:00 -05:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-182">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h2 id="constants">Constants</h2>
2013-03-18 01:06:33 -04:00
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-183">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-183">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2013-06-02 01:37:45 -04:00
</div>
2014-08-23 10:08:39 -04:00
<div class="content"><div class='highlight'><pre>
UTILITIES =</pre></div></div>
2014-01-29 23:54:00 -05:00
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-184">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-184">&#182;</a>
2013-06-02 01:37:45 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Correctly set up a prototype chain for inheritance, including a reference
to the superclass for <code>super()</code> calls, and copies of any static properties.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> extend: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-string">"
2014-01-29 23:54:00 -05:00
function(child, parent) {
for (var key in parent) {
2015-01-29 12:20:46 -05:00
if (<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(parent, key)) child[key] = parent[key];
2014-01-29 23:54:00 -05:00
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
}
"</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-185">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-185">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Create a function bound to the current value of “this”.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> bind: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'
2014-01-29 23:54:00 -05:00
function(fn, me){
return function(){
return fn.apply(me, arguments);
};
}
'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-186">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-186">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Discover if an item is in an array.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> indexOf: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"
2014-01-29 23:54:00 -05:00
[].indexOf || function(item) {
for (var i = 0, l = this.length; i &lt; l; i++) {
if (i in this &amp;&amp; this[i] === item) return i;
}
return -1;
}
"</span>
2016-09-22 16:19:43 -04:00
modulo: <span class="hljs-function">-&gt;</span> <span class="hljs-string">"""
2014-08-23 10:08:39 -04:00
function(a, b) { return (+a % (b = +b) + b) % b; }
2014-01-29 23:54:00 -05:00
"""</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-187">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-187">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Shortcuts to speed up the lookup time for native functions.</p>
</div>
2016-09-22 16:19:43 -04:00
<div class="content"><div class='highlight'><pre> hasProp: <span class="hljs-function">-&gt;</span> <span class="hljs-string">'{}.hasOwnProperty'</span>
slice : <span class="hljs-function">-&gt;</span> <span class="hljs-string">'[].slice'</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-188">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-188">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Levels indicate a nodes position in the AST. Useful for knowing if
2014-01-29 23:54:00 -05:00
parens are necessary or superfluous.</p>
</div>
2014-01-29 23:54:00 -05:00
<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>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-189">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-189">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Tabs are two spaces for pretty printing.</p>
</div>
2014-01-29 23:54:00 -05:00
<div class="content"><div class='highlight'><pre>TAB = <span class="hljs-string">' '</span>
2016-09-22 16:19:43 -04:00
SIMPLENUM = <span class="hljs-regexp">/^[+-]?\d+$/</span></pre></div></div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-190">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-190">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<h2 id="helper-functions">Helper Functions</h2>
</div>
</li>
2013-03-18 01:06:33 -04:00
2016-09-22 16:19:43 -04:00
<li id="section-191">
<div class="annotation">
2013-03-18 01:06:33 -04:00
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-191">&#182;</a>
2014-08-23 10:08:39 -04:00
</div>
</div>
</li>
2016-09-22 16:19:43 -04:00
<li id="section-192">
2014-08-23 10:08:39 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-192">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<p>Helper for ensuring that utility functions are assigned at the top level.</p>
</div>
2015-01-29 12:20:46 -05:00
<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>
2015-02-18 15:43:33 -05:00
ref = root.freeVariable name
2015-01-29 12:20:46 -05:00
root.assign ref, UTILITIES[name] o
root.utilities[name] = ref
2016-09-22 16:19:43 -04:00
<span class="hljs-function">
<span class="hljs-title">multident</span> = <span class="hljs-params">(code, tab)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
code = code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'$&amp;'</span> + tab
2016-09-22 16:19:43 -04:00
code.replace <span class="hljs-regexp">/\s+$/</span>, <span class="hljs-string">''</span>
<span class="hljs-function">
<span class="hljs-title">isLiteralArguments</span> = <span class="hljs-params">(node)</span> -&gt;</span>
2014-01-29 23:54:00 -05:00
node <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">is</span> <span class="hljs-string">'arguments'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> node.asKey
2016-09-22 16:19:43 -04:00
<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">and</span> <span class="hljs-keyword">not</span> node.asKey) <span class="hljs-keyword">or</span>
2014-01-29 23:54:00 -05:00
(node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound) <span class="hljs-keyword">or</span>
2016-09-22 16:19:43 -04:00
node <span class="hljs-keyword">instanceof</span> SuperCall
<span class="hljs-function">
<span class="hljs-title">isComplexOrAssignable</span> = <span class="hljs-params">(node)</span> -&gt;</span> node.isComplex() <span class="hljs-keyword">or</span> node.isAssignable?()</pre></div></div>
2013-06-02 01:37:45 -04:00
</li>
2016-09-22 16:19:43 -04:00
<li id="section-193">
2013-06-02 01:37:45 -04:00
<div class="annotation">
<div class="pilwrap ">
2016-09-22 16:19:43 -04:00
<a class="pilcrow" href="#section-193">&#182;</a>
2013-03-18 01:06:33 -04:00
</div>
2014-08-23 10:08:39 -04:00
<p>Unfold a nodes child if soak, then tuck the node under created <code>If</code></p>
2013-03-18 01:06:33 -04:00
</div>
2014-01-29 23:54:00 -05:00
<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>
2013-03-18 01:06:33 -04:00
</ul>
</div>
</body>
</html>