<!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 …</a> <a class="small" href="javascript:void(0);">+</a> <div id="jump_wrapper"> <div id="jump_page_wrapper"> <div id="jump_page"> <a class="source" href="browser.html"> browser.coffee </a> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="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> <ul class="sections"> <li id="title"> <div class="annotation"> <h1>nodes.coffee</h1> </div> </li> <li id="section-1"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-1">¶</a> </div> <p><code>nodes.coffee</code> contains all of the node classes for the syntax tree. Most nodes are created as the result of actions in the <a href="grammar.html">grammar</a>, but some are created by other nodes as a method of code generation. To convert the syntax tree into a string of JavaScript code, call <code>compile()</code> on the root.</p> </div> <div class="content"><div class='highlight'><pre> Error.stackTraceLimit = Infinity {Scope} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./scope'</span> {RESERVED, STRICT_PROSCRIBED} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./lexer'</span></pre></div></div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Import the helpers we plan to use.</p> </div> <div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, some, addLocationDataFn, locationDataToString, throwSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span></pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Functions required by parser</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.extend = extend <span class="hljs-built_in">exports</span>.addLocationDataFn = addLocationDataFn</pre></div></div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Constant functions for nodes that don’t need customization.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">YES</span> = -></span> <span class="hljs-literal">yes</span> <span class="hljs-function"><span class="hljs-title">NO</span> = -></span> <span class="hljs-literal">no</span> <span class="hljs-function"><span class="hljs-title">THIS</span> = -></span> <span class="hljs-keyword">this</span> <span class="hljs-function"><span class="hljs-title">NEGATE</span> = -></span> <span class="hljs-property">@negated</span> = <span class="hljs-keyword">not</span> <span class="hljs-property">@negated</span>; <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">¶</a> </div> <h3 id="codefragment">CodeFragment</h3> </div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-6">¶</a> </div> <p>The various nodes defined below all compile to a collection of <strong>CodeFragment</strong> objects. A CodeFragments is a block of generated code, and the location in the source file where the code came from. CodeFragments can be assembled together into working code just by catting together all the CodeFragments’ <code>code</code> snippets, in order.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.CodeFragment = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CodeFragment</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(parent, code)</span> -></span> <span class="hljs-property">@code</span> = <span class="hljs-string">"<span class="hljs-subst">#{code}</span>"</span> <span class="hljs-property">@locationData</span> = parent?.locationData <span class="hljs-property">@type</span> = parent?.constructor?.name <span class="hljs-keyword">or</span> <span class="hljs-string">'unknown'</span> <span class="hljs-attribute">toString</span>:<span class="hljs-function"> -></span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@code</span>}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@locationData</span> <span class="hljs-keyword">then</span> <span class="hljs-string">": "</span> + locationDataToString(<span class="hljs-property">@locationData</span>) <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span></pre></div></div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Convert an array of CodeFragments into a string.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">fragmentsToText</span> = <span class="hljs-params">(fragments)</span> -></span> (fragment.code <span class="hljs-keyword">for</span> fragment <span class="hljs-keyword">in</span> fragments).join(<span class="hljs-string">''</span>)</pre></div></div> </li> <li id="section-8"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-8">¶</a> </div> <h3 id="base">Base</h3> </div> </li> <li id="section-9"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-9">¶</a> </div> <p>The <strong>Base</strong> is the abstract base class for all nodes in the syntax tree. Each subclass implements the <code>compileNode</code> method, which performs the code generation for that node. To compile a node to JavaScript, call <code>compile</code> on it, which wraps <code>compileNode</code> in some generic extra smarts, to know when the generated code needs to be wrapped up in a closure. An options hash is passed and cloned throughout, containing information about the environment from higher in the tree (such as if a returned value is being requested by the surrounding function), information about the current scope, and indentation level.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Base = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">compile</span>: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -></span> fragmentsToText <span class="hljs-property">@compileToFragments</span> o, lvl</pre></div></div> </li> <li id="section-10"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Common logic for determining whether to wrap this node in a closure before compiling it, or to compile directly. We need to wrap if this node is a <em>statement</em>, and it’s not a <em>pureStatement</em>, and we’re not at the top level of a block (which would be unnecessary), and we haven’t already been asked to return the result (because statements know how to return results).</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o, lvl)</span> -></span> o = extend {}, o o.level = lvl <span class="hljs-keyword">if</span> lvl node = <span class="hljs-property">@unfoldSoak</span>(o) <span class="hljs-keyword">or</span> <span class="hljs-keyword">this</span> node.tab = o.indent <span class="hljs-keyword">if</span> o.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> node.isStatement(o) node.compileNode o <span class="hljs-keyword">else</span> node.compileClosure o</pre></div></div> </li> <li id="section-11"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Statements converted into expressions via closure-wrapping share a scope object with their parent closure, to preserve the expected lexical scope.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileClosure</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> jumpNode = <span class="hljs-property">@jumps</span>() jumpNode.error <span class="hljs-string">'cannot use a pure statement in an expression'</span> o.sharedScope = <span class="hljs-literal">yes</span> func = <span class="hljs-keyword">new</span> Code [], Block.wrap [<span class="hljs-keyword">this</span>] args = [] <span class="hljs-keyword">if</span> (argumentsNode = <span class="hljs-property">@contains</span> isLiteralArguments) <span class="hljs-keyword">or</span> <span class="hljs-property">@contains</span> isLiteralThis args = [<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'this'</span>] <span class="hljs-keyword">if</span> argumentsNode meth = <span class="hljs-string">'apply'</span> args.push <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'arguments'</span> <span class="hljs-keyword">else</span> meth = <span class="hljs-string">'call'</span> func = <span class="hljs-keyword">new</span> Value func, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal meth] parts = (<span class="hljs-keyword">new</span> Call func, args).compileNode o <span class="hljs-keyword">if</span> func.isGenerator <span class="hljs-keyword">or</span> func.base?.isGenerator parts.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"(yield* "</span> parts.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">")"</span> parts</pre></div></div> </li> <li id="section-12"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-12">¶</a> </div> <p>If the code generation wishes to use the result of a complex expression in multiple places, ensure that the expression is only ever evaluated once, by assigning it to a temporary variable. Pass a level to precompile.</p> <p>If <code>level</code> is passed, then returns <code>[val, ref]</code>, where <code>val</code> is the compiled value, and <code>ref</code> is the compiled reference. If <code>level</code> is not passed, this returns <code>[val, ref]</code> where the two values are raw nodes which have not been compiled.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">cache</span>: <span class="hljs-function"><span class="hljs-params">(o, level, isComplex)</span> -></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> <span class="hljs-property">@isComplex</span>() <span class="hljs-keyword">if</span> complex ref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'ref'</span> sub = <span class="hljs-keyword">new</span> Assign ref, <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> [sub.compileToFragments(o, level), [<span class="hljs-property">@makeCode</span>(ref.value)]] <span class="hljs-keyword">else</span> [sub, ref] <span class="hljs-keyword">else</span> ref = <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> <span class="hljs-property">@compileToFragments</span> o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span> [ref, ref] <span class="hljs-attribute">cacheToCodeFragments</span>: <span class="hljs-function"><span class="hljs-params">(cacheValues)</span> -></span> [fragmentsToText(cacheValues[<span class="hljs-number">0</span>]), fragmentsToText(cacheValues[<span class="hljs-number">1</span>])]</pre></div></div> </li> <li id="section-13"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Construct a node that returns the current node’s result. Note that this is overridden for smarter behavior for many statement nodes (e.g. If, For)…</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> me = <span class="hljs-property">@unwrapAll</span>() <span class="hljs-keyword">if</span> res <span class="hljs-keyword">new</span> Call <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">"<span class="hljs-subst">#{res}</span>.push"</span>), [me] <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Return me</pre></div></div> </li> <li id="section-14"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Does this node, or any of its children, contain a node of a certain kind? Recursively traverses down the <em>children</em> nodes and returns the first one that verifies <code>pred</code>. Otherwise return undefined. <code>contains</code> does not cross scope boundaries.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">contains</span>: <span class="hljs-function"><span class="hljs-params">(pred)</span> -></span> node = <span class="hljs-literal">undefined</span> <span class="hljs-property">@traverseChildren</span> <span class="hljs-literal">no</span>, <span class="hljs-function"><span class="hljs-params">(n)</span> -></span> <span class="hljs-keyword">if</span> pred n node = n <span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> node</pre></div></div> </li> <li id="section-15"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Pull out the last non-comment node of a node list.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">lastNonComment</span>: <span class="hljs-function"><span class="hljs-params">(list)</span> -></span> i = list.length <span class="hljs-keyword">return</span> list[i] <span class="hljs-keyword">while</span> i-- <span class="hljs-keyword">when</span> list[i] <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-literal">null</span></pre></div></div> </li> <li id="section-16"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-16">¶</a> </div> <p><code>toString</code> representation of the node, for inspecting the parse tree. This is what <code>coffee --nodes</code> prints out.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">toString</span>: <span class="hljs-function"><span class="hljs-params">(idt = <span class="hljs-string">''</span>, name = <span class="hljs-property">@constructor</span>.name)</span> -></span> tree = <span class="hljs-string">'\n'</span> + idt + name tree += <span class="hljs-string">'?'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@soak</span> <span class="hljs-property">@eachChild</span> <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> tree += node.toString idt + TAB tree</pre></div></div> </li> <li id="section-17"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Passes each child to a function, breaking when the function returns <code>false</code>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">eachChild</span>: <span class="hljs-function"><span class="hljs-params">(func)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@children</span> <span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> <span class="hljs-property">@children</span> <span class="hljs-keyword">when</span> @[attr] <span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> flatten [@[attr]] <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> func(child) <span class="hljs-keyword">is</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">this</span> <span class="hljs-attribute">traverseChildren</span>: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -></span> <span class="hljs-property">@eachChild</span> <span class="hljs-function"><span class="hljs-params">(child)</span> -></span> recur = func(child) child.traverseChildren(crossScope, func) <span class="hljs-keyword">unless</span> recur <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span> <span class="hljs-attribute">invert</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span> <span class="hljs-attribute">unwrapAll</span>:<span class="hljs-function"> -></span> node = <span class="hljs-keyword">this</span> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">until</span> node <span class="hljs-keyword">is</span> node = node.unwrap() node</pre></div></div> </li> <li id="section-18"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-18">¶</a> </div> <p>Default implementations of the common node properties and methods. Nodes will override these with custom logic, if needed.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">children</span>: [] isStatement : NO jumps : NO isComplex : YES isChainable : NO isAssignable : NO unwrap : THIS unfoldSoak : NO</pre></div></div> </li> <li id="section-19"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-19">¶</a> </div> <p>Is this node used to assign a certain variable?</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">assigns</span>: NO</pre></div></div> </li> <li id="section-20"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-20">¶</a> </div> <p>For this node and all descendents, set the location data to <code>locationData</code> if the location data is not already set.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">updateLocationDataIfMissing</span>: <span class="hljs-function"><span class="hljs-params">(locationData)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@locationData</span> <span class="hljs-property">@locationData</span> = locationData <span class="hljs-property">@eachChild</span> <span class="hljs-function"><span class="hljs-params">(child)</span> -></span> child.updateLocationDataIfMissing locationData</pre></div></div> </li> <li id="section-21"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-21">¶</a> </div> <p>Throw a SyntaxError associated with this node’s location.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">error</span>: <span class="hljs-function"><span class="hljs-params">(message)</span> -></span> throwSyntaxError message, <span class="hljs-property">@locationData</span> <span class="hljs-attribute">makeCode</span>: <span class="hljs-function"><span class="hljs-params">(code)</span> -></span> <span class="hljs-keyword">new</span> CodeFragment <span class="hljs-keyword">this</span>, code <span class="hljs-attribute">wrapInBraces</span>: <span class="hljs-function"><span class="hljs-params">(fragments)</span> -></span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">'('</span>), fragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">')'</span>)</pre></div></div> </li> <li id="section-22"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-22">¶</a> </div> <p><code>fragmentsList</code> is an array of arrays of fragments. Each array in fragmentsList will be concatonated together, with <code>joinStr</code> added in between each, to produce a final flat array of fragments.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">joinFragmentArrays</span>: <span class="hljs-function"><span class="hljs-params">(fragmentsList, joinStr)</span> -></span> answer = [] <span class="hljs-keyword">for</span> fragments,i <span class="hljs-keyword">in</span> fragmentsList <span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> joinStr answer = answer.concat fragments answer</pre></div></div> </li> <li id="section-23"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-23">¶</a> </div> <h3 id="block">Block</h3> </div> </li> <li id="section-24"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-24">¶</a> </div> <p>The block is the list of expressions that forms the body of an indented block of code — the implementation of a function, a clause in an <code>if</code>, <code>switch</code>, or <code>try</code>, and so on…</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Block = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Block</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -></span> <span class="hljs-property">@expressions</span> = compact flatten nodes <span class="hljs-keyword">or</span> [] <span class="hljs-attribute">children</span>: [<span class="hljs-string">'expressions'</span>]</pre></div></div> </li> <li id="section-25"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Tack an expression on to the end of this expression list.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">push</span>: <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> <span class="hljs-property">@expressions</span>.push node <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-26"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-26">¶</a> </div> <p>Remove and return the last expression of this expression list.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">pop</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@expressions</span>.pop()</pre></div></div> </li> <li id="section-27"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Add an expression at the beginning of this expression list.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unshift</span>: <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> <span class="hljs-property">@expressions</span>.unshift node <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-28"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-28">¶</a> </div> <p>If this Block consists of just a single node, unwrap it by pulling it back out.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unwrap</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@expressions</span>.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@expressions</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-29"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-29">¶</a> </div> <p>Is this an empty block of code?</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">isEmpty</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@expressions</span>.length <span class="hljs-attribute">isStatement</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">for</span> exp <span class="hljs-keyword">in</span> <span class="hljs-property">@expressions</span> <span class="hljs-keyword">when</span> exp.isStatement o <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-literal">no</span> <span class="hljs-attribute">jumps</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">for</span> exp <span class="hljs-keyword">in</span> <span class="hljs-property">@expressions</span> <span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = exp.jumps o</pre></div></div> </li> <li id="section-30"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-30">¶</a> </div> <p>A Block node does not return its entire body, rather it ensures that the final expression is returned.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> len = <span class="hljs-property">@expressions</span>.length <span class="hljs-keyword">while</span> len-- expr = <span class="hljs-property">@expressions</span>[len] <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-property">@expressions</span>[len] = expr.makeReturn res <span class="hljs-property">@expressions</span>.splice(len, <span class="hljs-number">1</span>) <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> expr.expression <span class="hljs-keyword">break</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-31"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-31">¶</a> </div> <p>A <strong>Block</strong> is the only node that can serve as the root.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o = {}, level)</span> -></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> <span class="hljs-property">@compileRoot</span> o</pre></div></div> </li> <li id="section-32"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Compile all expressions within the <strong>Block</strong> body. If we need to return the result, and it’s an expression, simply return it. If it’s a statement, ask the statement to do so.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@tab</span> = o.indent top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP compiledNodes = [] <span class="hljs-keyword">for</span> node, index <span class="hljs-keyword">in</span> <span class="hljs-property">@expressions</span> node = node.unwrapAll() node = (node.unfoldSoak(o) <span class="hljs-keyword">or</span> node) <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Block</pre></div></div> </li> <li id="section-33"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-33">¶</a> </div> <p>This is a nested block. We don’t do anything special here like enclose it in a new scope; we just compile the statements in this block along with our own</p> </div> <div class="content"><div class='highlight'><pre> compiledNodes.push node.compileNode o <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> top node.front = <span class="hljs-literal">true</span> fragments = node.compileToFragments o <span class="hljs-keyword">unless</span> node.isStatement o fragments.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>"</span> fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">";"</span> compiledNodes.push fragments <span class="hljs-keyword">else</span> compiledNodes.push node.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">if</span> top <span class="hljs-keyword">if</span> <span class="hljs-property">@spaced</span> <span class="hljs-keyword">return</span> [].concat <span class="hljs-property">@joinFragmentArrays</span>(compiledNodes, <span class="hljs-string">'\n\n'</span>), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>) <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-property">@joinFragmentArrays</span>(compiledNodes, <span class="hljs-string">'\n'</span>) <span class="hljs-keyword">if</span> compiledNodes.length answer = <span class="hljs-property">@joinFragmentArrays</span>(compiledNodes, <span class="hljs-string">', '</span>) <span class="hljs-keyword">else</span> answer = [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"void 0"</span>] <span class="hljs-keyword">if</span> compiledNodes.length > <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> o.level >= LEVEL_LIST <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer</pre></div></div> </li> <li id="section-34"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-34">¶</a> </div> <p>If we happen to be the top-level <strong>Block</strong>, wrap everything in a safety closure, unless requested not to. It would be better not to generate them in the first place, but for now, clean up obvious double-parentheses.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileRoot</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o.indent = <span class="hljs-keyword">if</span> o.bare <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> TAB o.level = LEVEL_TOP <span class="hljs-property">@spaced</span> = <span class="hljs-literal">yes</span> o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-literal">null</span>, o.referencedVars ? []</pre></div></div> </li> <li id="section-35"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-35">¶</a> </div> <p>Mark given local variables in the root scope as parameters so they don’t end up being declared on this block.</p> </div> <div class="content"><div class='highlight'><pre> o.scope.parameter name <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> o.locals <span class="hljs-keyword">or</span> [] prelude = [] <span class="hljs-keyword">unless</span> o.bare preludeExps = <span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> <span class="hljs-property">@expressions</span> <span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp.unwrap() <span class="hljs-keyword">instanceof</span> Comment exp rest = <span class="hljs-property">@expressions</span>[preludeExps.length...] <span class="hljs-property">@expressions</span> = preludeExps <span class="hljs-keyword">if</span> preludeExps.length prelude = <span class="hljs-property">@compileNode</span> merge(o, <span class="hljs-attribute">indent</span>: <span class="hljs-string">''</span>) prelude.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n"</span> <span class="hljs-property">@expressions</span> = rest fragments = <span class="hljs-property">@compileWithDeclarations</span> o <span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> o.bare [].concat prelude, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"(function() {\n"</span>), fragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n}).call(this);\n"</span>)</pre></div></div> </li> <li id="section-36"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-36">¶</a> </div> <p>Compile the expressions body for the contents of a function, with declarations of all inner variables pushed up to the top.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileWithDeclarations</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> fragments = [] post = [] <span class="hljs-keyword">for</span> exp, i <span class="hljs-keyword">in</span> <span class="hljs-property">@expressions</span> exp = exp.unwrap() <span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> exp <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-keyword">or</span> exp <span class="hljs-keyword">instanceof</span> Literal o = merge(o, <span class="hljs-attribute">level</span>: LEVEL_TOP) <span class="hljs-keyword">if</span> i rest = <span class="hljs-property">@expressions</span>.splice i, <span class="hljs-number">9e9</span> [spaced, <span class="hljs-property">@spaced</span>] = [<span class="hljs-property">@spaced</span>, <span class="hljs-literal">no</span>] [fragments, <span class="hljs-property">@spaced</span>] = [<span class="hljs-property">@compileNode</span>(o), spaced] <span class="hljs-property">@expressions</span> = rest post = <span class="hljs-property">@compileNode</span> o {scope} = o <span class="hljs-keyword">if</span> scope.expressions <span class="hljs-keyword">is</span> <span class="hljs-keyword">this</span> declars = o.scope.hasDeclarations() assigns = scope.hasAssignments <span class="hljs-keyword">if</span> declars <span class="hljs-keyword">or</span> assigns fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> i fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>var "</span> <span class="hljs-keyword">if</span> declars fragments.push <span class="hljs-property">@makeCode</span> scope.declaredVariables().join(<span class="hljs-string">', '</span>) <span class="hljs-keyword">if</span> assigns fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">",\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span> + TAB}</span>"</span> <span class="hljs-keyword">if</span> declars fragments.push <span class="hljs-property">@makeCode</span> scope.assignedVariables().join(<span class="hljs-string">",\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span> + TAB}</span>"</span>) fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">";\n<span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@spaced</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> fragments.length <span class="hljs-keyword">and</span> post.length fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n"</span> fragments.concat post</pre></div></div> </li> <li id="section-37"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-37">¶</a> </div> <p>Wrap up the given nodes as a <strong>Block</strong>, unless it already happens to be one.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-property">@wrap</span>: <span class="hljs-function"><span class="hljs-params">(nodes)</span> -></span> <span class="hljs-keyword">return</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> nodes.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> nodes[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> Block <span class="hljs-keyword">new</span> Block nodes</pre></div></div> </li> <li id="section-38"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-38">¶</a> </div> <h3 id="literal">Literal</h3> </div> </li> <li id="section-39"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-39">¶</a> </div> <p>Literals are static values that can be passed through directly into JavaScript without translation, such as: strings, numbers, <code>true</code>, <code>false</code>, <code>null</code>…</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Literal = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Literal</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@value</span>)</span> -></span> <span class="hljs-attribute">makeReturn</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isStatement</span>() <span class="hljs-keyword">then</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span> <span class="hljs-attribute">isAssignable</span>:<span class="hljs-function"> -></span> IDENTIFIER.test <span class="hljs-property">@value</span> <span class="hljs-attribute">isStatement</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@value</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'break'</span>, <span class="hljs-string">'continue'</span>, <span class="hljs-string">'debugger'</span>] <span class="hljs-attribute">isComplex</span>: NO <span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> name <span class="hljs-keyword">is</span> <span class="hljs-property">@value</span> <span class="hljs-attribute">jumps</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span> <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> <span class="hljs-property">@value</span> <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> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> code = <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span> <span class="hljs-keyword">is</span> <span class="hljs-string">'this'</span> <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> <span class="hljs-property">@value</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span>.reserved <span class="hljs-string">"\"<span class="hljs-subst">#{<span class="hljs-property">@value</span>}</span>\""</span> <span class="hljs-keyword">else</span> <span class="hljs-property">@value</span> answer = <span class="hljs-keyword">if</span> <span class="hljs-property">@isStatement</span>() <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{code}</span>;"</span> <span class="hljs-keyword">else</span> code [<span class="hljs-property">@makeCode</span> answer] <span class="hljs-attribute">toString</span>:<span class="hljs-function"> -></span> <span class="hljs-string">' "'</span> + <span class="hljs-property">@value</span> + <span class="hljs-string">'"'</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exports</span>.<span class="hljs-title">Undefined</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">isAssignable</span>: NO <span class="hljs-attribute">isComplex</span>: NO <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [<span class="hljs-property">@makeCode</span> <span class="hljs-keyword">if</span> o.level >= 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>] <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exports</span>.<span class="hljs-title">Null</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">isAssignable</span>: NO <span class="hljs-attribute">isComplex</span>: NO <span class="hljs-attribute">compileNode</span>:<span class="hljs-function"> -></span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"null"</span>] <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exports</span>.<span class="hljs-title">Bool</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">isAssignable</span>: NO <span class="hljs-attribute">isComplex</span>: NO <span class="hljs-attribute">compileNode</span>:<span class="hljs-function"> -></span> [<span class="hljs-property">@makeCode</span> <span class="hljs-property">@val</span>] <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@val</span>)</span> -></span></pre></div></div> </li> <li id="section-40"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-40">¶</a> </div> <h3 id="return">Return</h3> </div> </li> <li id="section-41"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-41">¶</a> </div> <p>A <code>return</code> is a <em>pureStatement</em> — wrapping it in a closure wouldn’t make sense.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Return = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Return</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@expression</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'expression'</span>] <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">makeReturn</span>: THIS <span class="hljs-attribute">jumps</span>: THIS <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -></span> expr = <span class="hljs-property">@expression</span>?.makeReturn() <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">and</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">then</span> expr.compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span> o, level <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> answer = [] exprIsYieldReturn = <span class="hljs-property">@expression</span>?.isYieldReturn?()</pre></div></div> </li> <li id="section-42"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-42">¶</a> </div> <p>TODO: If we call expression.compile() here twice, we’ll sometimes get back different results!</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> exprIsYieldReturn answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-property">@tab</span> + <span class="hljs-string">"return<span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@expression</span> <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> <span class="hljs-property">@expression</span> answer = answer.concat <span class="hljs-property">@expression</span>.compileToFragments o, LEVEL_PAREN answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">";"</span> <span class="hljs-keyword">unless</span> exprIsYieldReturn <span class="hljs-keyword">return</span> answer</pre></div></div> </li> <li id="section-43"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-43">¶</a> </div> <h3 id="value">Value</h3> </div> </li> <li id="section-44"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-44">¶</a> </div> <p>A value, variable or literal or parenthesized, indexed or dotted into, or vanilla.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Value = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Value</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(base, props, tag)</span> -></span> <span class="hljs-keyword">return</span> base <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> props <span class="hljs-keyword">and</span> base <span class="hljs-keyword">instanceof</span> Value <span class="hljs-property">@base</span> = base <span class="hljs-property">@properties</span> = props <span class="hljs-keyword">or</span> [] @[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> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'base'</span>, <span class="hljs-string">'properties'</span>]</pre></div></div> </li> <li id="section-45"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-45">¶</a> </div> <p>Add a property (or <em>properties</em> ) <code>Access</code> to the list.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">add</span>: <span class="hljs-function"><span class="hljs-params">(props)</span> -></span> <span class="hljs-property">@properties</span> = <span class="hljs-property">@properties</span>.concat props <span class="hljs-keyword">this</span> <span class="hljs-attribute">hasProperties</span>:<span class="hljs-function"> -></span> !!<span class="hljs-property">@properties</span>.length <span class="hljs-attribute">bareLiteral</span>: <span class="hljs-function"><span class="hljs-params">(type)</span> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">and</span> <span class="hljs-property">@base</span> <span class="hljs-keyword">instanceof</span> type</pre></div></div> </li> <li id="section-46"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-46">¶</a> </div> <p>Some boolean checks for the benefit of other nodes.</p> </div> <div class="content"><div class='highlight'><pre> isArray :<span class="hljs-function"> -></span> <span class="hljs-property">@bareLiteral</span>(Arr) isRange :<span class="hljs-function"> -></span> <span class="hljs-property">@bareLiteral</span>(Range) isComplex :<span class="hljs-function"> -></span> <span class="hljs-property">@hasProperties</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@base</span>.isComplex() isAssignable :<span class="hljs-function"> -></span> <span class="hljs-property">@hasProperties</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@base</span>.isAssignable() isSimpleNumber :<span class="hljs-function"> -></span> <span class="hljs-property">@bareLiteral</span>(Literal) <span class="hljs-keyword">and</span> SIMPLENUM.test <span class="hljs-property">@base</span>.value isString :<span class="hljs-function"> -></span> <span class="hljs-property">@bareLiteral</span>(Literal) <span class="hljs-keyword">and</span> IS_STRING.test <span class="hljs-property">@base</span>.value isRegex :<span class="hljs-function"> -></span> <span class="hljs-property">@bareLiteral</span>(Literal) <span class="hljs-keyword">and</span> IS_REGEX.test <span class="hljs-property">@base</span>.value isAtomic :<span class="hljs-function"> -></span> <span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> <span class="hljs-property">@properties</span>.concat <span class="hljs-property">@base</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> node.soak <span class="hljs-keyword">or</span> node <span class="hljs-keyword">instanceof</span> Call <span class="hljs-literal">yes</span> isNotCallable :<span class="hljs-function"> -></span> <span class="hljs-property">@isSimpleNumber</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isString</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isRegex</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isArray</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isRange</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isSplice</span>() <span class="hljs-keyword">or</span> <span class="hljs-property">@isObject</span>() isStatement : <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">and</span> <span class="hljs-property">@base</span>.isStatement o assigns : <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">and</span> <span class="hljs-property">@base</span>.assigns name jumps : <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">and</span> <span class="hljs-property">@base</span>.jumps o <span class="hljs-attribute">isObject</span>: <span class="hljs-function"><span class="hljs-params">(onlyGenerated)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@properties</span>.length (<span class="hljs-property">@base</span> <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> <span class="hljs-property">@base</span>.generated) <span class="hljs-attribute">isSplice</span>:<span class="hljs-function"> -></span> [..., lastProp] = <span class="hljs-property">@properties</span> lastProp <span class="hljs-keyword">instanceof</span> Slice <span class="hljs-attribute">looksStatic</span>: <span class="hljs-function"><span class="hljs-params">(className)</span> -></span> <span class="hljs-property">@base</span>.value <span class="hljs-keyword">is</span> className <span class="hljs-keyword">and</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@properties</span>[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'prototype'</span></pre></div></div> </li> <li id="section-47"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-47">¶</a> </div> <p>The value can be unwrapped as its inner node, if there are no attached properties.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unwrap</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">then</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> <span class="hljs-property">@base</span></pre></div></div> </li> <li id="section-48"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-48">¶</a> </div> <p>A reference has base part (<code>this</code> value) and name part. We cache them separately for compiling complex expressions. <code>a()[b()] ?= c</code> -> <code>(_base = a())[_name = b()] ? _base[_name] = c</code></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">cacheReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [..., name] = <span class="hljs-property">@properties</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@properties</span>.length < <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@base</span>.isComplex() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> name?.isComplex() <span class="hljs-keyword">return</span> [<span class="hljs-keyword">this</span>, <span class="hljs-keyword">this</span>] <span class="hljs-comment"># `a` `a.b`</span> base = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@base</span>, <span class="hljs-property">@properties</span>[...-<span class="hljs-number">1</span>] <span class="hljs-keyword">if</span> base.isComplex() <span class="hljs-comment"># `a().b`</span> bref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'base'</span> base = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign bref, base <span class="hljs-keyword">return</span> [base, bref] <span class="hljs-keyword">unless</span> name <span class="hljs-comment"># `a()`</span> <span class="hljs-keyword">if</span> name.isComplex() <span class="hljs-comment"># `a[b()]`</span> nref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'name'</span> name = <span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> Assign nref, name.index nref = <span class="hljs-keyword">new</span> Index nref [base.add(name), <span class="hljs-keyword">new</span> Value(bref <span class="hljs-keyword">or</span> base.base, [nref <span class="hljs-keyword">or</span> name])]</pre></div></div> </li> <li id="section-49"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-49">¶</a> </div> <p>We compile a value to JavaScript by compiling and joining each property. Things get much more interesting if the chain of properties has <em>soak</em> operators <code>?.</code> interspersed. Then we have to take care not to accidentally evaluate anything twice when building the soak chain.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@base</span>.front = <span class="hljs-property">@front</span> props = <span class="hljs-property">@properties</span> fragments = <span class="hljs-property">@base</span>.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> (<span class="hljs-property">@base</span> <span class="hljs-keyword">instanceof</span> Parens <span class="hljs-keyword">or</span> props.length) <span class="hljs-keyword">and</span> SIMPLENUM.test fragmentsToText fragments fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">'.'</span> <span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> props fragments.push (prop.compileToFragments o)... fragments</pre></div></div> </li> <li id="section-50"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -> <code>a.b if a?</code></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unfoldSoak</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@unfoldedSoak</span> ?= <span class="hljs-keyword">do</span><span class="hljs-function"> =></span> <span class="hljs-keyword">if</span> ifn = <span class="hljs-property">@base</span>.unfoldSoak o ifn.body.properties.push <span class="hljs-property">@properties</span>... <span class="hljs-keyword">return</span> ifn <span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> <span class="hljs-property">@properties</span> <span class="hljs-keyword">when</span> prop.soak prop.soak = <span class="hljs-literal">off</span> fst = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@base</span>, <span class="hljs-property">@properties</span>[...i] snd = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@base</span>, <span class="hljs-property">@properties</span>[i..] <span class="hljs-keyword">if</span> fst.isComplex() ref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'ref'</span> fst = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign ref, fst snd.base = ref <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If <span class="hljs-keyword">new</span> Existence(fst), snd, <span class="hljs-attribute">soak</span>: <span class="hljs-literal">on</span> <span class="hljs-literal">no</span></pre></div></div> </li> <li id="section-51"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-51">¶</a> </div> <h3 id="comment">Comment</h3> </div> </li> <li id="section-52"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-52">¶</a> </div> <p>CoffeeScript passes through block comments as JavaScript block comments at the same position.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.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> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@comment</span>)</span> -></span> <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">makeReturn</span>: THIS <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -></span> comment = <span class="hljs-property">@comment</span>.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, <span class="hljs-property">@tab</span>}</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">#{<span class="hljs-property">@tab</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span> */"</span> code = o.indent + code <span class="hljs-keyword">if</span> (level <span class="hljs-keyword">or</span> o.level) <span class="hljs-keyword">is</span> LEVEL_TOP [<span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), <span class="hljs-property">@makeCode</span>(code)]</pre></div></div> </li> <li id="section-53"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-53">¶</a> </div> <h3 id="call">Call</h3> </div> </li> <li id="section-54"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-54">¶</a> </div> <p>Node for a function invocation. Takes care of converting <code>super()</code> calls into calls against the prototype’s function of the same name.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Call = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Call</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(variable, <span class="hljs-property">@args</span> = [], <span class="hljs-property">@soak</span>)</span> -></span> <span class="hljs-property">@isNew</span> = <span class="hljs-literal">false</span> <span class="hljs-property">@isSuper</span> = variable <span class="hljs-keyword">is</span> <span class="hljs-string">'super'</span> <span class="hljs-property">@variable</span> = <span class="hljs-keyword">if</span> <span class="hljs-property">@isSuper</span> <span class="hljs-keyword">then</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">else</span> variable <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> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'args'</span>]</pre></div></div> </li> <li id="section-55"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-55">¶</a> </div> <p>Tag this invocation as creating a new instance.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">newInstance</span>:<span class="hljs-function"> -></span> base = <span class="hljs-property">@variable</span>?.base <span class="hljs-keyword">or</span> <span class="hljs-property">@variable</span> <span class="hljs-keyword">if</span> base <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> base.isNew base.newInstance() <span class="hljs-keyword">else</span> <span class="hljs-property">@isNew</span> = <span class="hljs-literal">true</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-56"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-56">¶</a> </div> <p>Grab the reference to the superclass’s implementation of the current method.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">superReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></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> Literal 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> Literal 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> Literal <span class="hljs-string">'__super__'</span>] accesses.push <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <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> <span class="hljs-property">@error</span> <span class="hljs-string">'cannot call super outside of an instance method.'</span></pre></div></div> </li> <li id="section-57"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-57">¶</a> </div> <p>The appropriate <code>this</code> value for a <code>super</code> call.</p> </div> <div class="content"><div class='highlight'><pre> superThis : <span class="hljs-function"><span class="hljs-params">(o)</span> -></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> </li> <li id="section-58"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-58">¶</a> </div> <p>Soaked chained invocations unfold into if/else ternary structures.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unfoldSoak</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@soak</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</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(<span class="hljs-property">@variable</span>).cacheReference o <span class="hljs-keyword">else</span> left = <span class="hljs-keyword">new</span> Literal <span class="hljs-property">@superReference</span> o rite = <span class="hljs-keyword">new</span> Value left rite = <span class="hljs-keyword">new</span> Call rite, <span class="hljs-property">@args</span> rite.isNew = <span class="hljs-property">@isNew</span> left = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"typeof <span class="hljs-subst">#{ left.compile o }</span> === \"function\""</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If left, <span class="hljs-keyword">new</span> Value(rite), <span class="hljs-attribute">soak</span>: <span class="hljs-literal">yes</span> call = <span class="hljs-keyword">this</span> list = [] <span class="hljs-keyword">loop</span> <span class="hljs-keyword">if</span> call.variable <span class="hljs-keyword">instanceof</span> Call list.push call call = call.variable <span class="hljs-keyword">continue</span> <span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> call.variable <span class="hljs-keyword">instanceof</span> Value list.push call <span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> (call = call.variable.base) <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">for</span> call <span class="hljs-keyword">in</span> list.reverse() <span class="hljs-keyword">if</span> ifn <span class="hljs-keyword">if</span> call.variable <span class="hljs-keyword">instanceof</span> Call call.variable = ifn <span class="hljs-keyword">else</span> call.variable.base = ifn ifn = unfoldSoak o, call, <span class="hljs-string">'variable'</span> ifn</pre></div></div> </li> <li id="section-59"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-59">¶</a> </div> <p>Compile a vanilla function call.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@variable</span>?.front = <span class="hljs-property">@front</span> compiledArray = Splat.compileSplattedArray o, <span class="hljs-property">@args</span>, <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> compiledArray.length <span class="hljs-keyword">return</span> <span class="hljs-property">@compileSplat</span> o, compiledArray compiledArgs = [] <span class="hljs-keyword">for</span> arg, argIndex <span class="hljs-keyword">in</span> <span class="hljs-property">@args</span> <span class="hljs-keyword">if</span> argIndex <span class="hljs-keyword">then</span> compiledArgs.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">", "</span> compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)... fragments = [] <span class="hljs-keyword">if</span> <span class="hljs-property">@isSuper</span> preface = <span class="hljs-property">@superReference</span>(o) + <span class="hljs-string">".call(<span class="hljs-subst">#{<span class="hljs-property">@superThis</span>(o)}</span>"</span> <span class="hljs-keyword">if</span> compiledArgs.length <span class="hljs-keyword">then</span> preface += <span class="hljs-string">", "</span> fragments.push <span class="hljs-property">@makeCode</span> preface <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isNew</span> <span class="hljs-keyword">then</span> fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">'new '</span> fragments.push <span class="hljs-property">@variable</span>.compileToFragments(o, LEVEL_ACCESS)... fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"("</span> fragments.push compiledArgs... fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">")"</span> fragments</pre></div></div> </li> <li id="section-60"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-60">¶</a> </div> <p>If you call a function with a splat, it’s converted into a JavaScript <code>.apply()</code> call to allow an array of arguments to be passed. If it’s a constructor, then things get real tricky. We have to inject an inner constructor in order to be able to pass the varargs.</p> <p>splatArgs is an array of CodeFragments to put into the ‘apply’.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileSplat</span>: <span class="hljs-function"><span class="hljs-params">(o, splatArgs)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isSuper</span> <span class="hljs-keyword">return</span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"<span class="hljs-subst">#{ <span class="hljs-property">@superReference</span> o }</span>.apply(<span class="hljs-subst">#{<span class="hljs-property">@superThis</span>(o)}</span>, "</span>), splatArgs, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">")"</span>) <span class="hljs-keyword">if</span> <span class="hljs-property">@isNew</span> idt = <span class="hljs-property">@tab</span> + TAB <span class="hljs-keyword">return</span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">""" (function(func, args, ctor) { <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; <span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>})("""</span>), (<span class="hljs-property">@variable</span>.compileToFragments o, LEVEL_LIST), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">", "</span>), splatArgs, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">", function(){})"</span>) answer = [] base = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@variable</span> <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> answer = answer.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"(<span class="hljs-subst">#{ref}</span> = "</span>), (base.compileToFragments o, LEVEL_LIST), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">")"</span>), name.compileToFragments(o) <span class="hljs-keyword">else</span> fun = base.compileToFragments o, LEVEL_ACCESS fun = <span class="hljs-property">@wrapInBraces</span> fun <span class="hljs-keyword">if</span> SIMPLENUM.test fragmentsToText fun <span class="hljs-keyword">if</span> name ref = fragmentsToText fun fun.push (name.compileToFragments o)... <span class="hljs-keyword">else</span> ref = <span class="hljs-string">'null'</span> answer = answer.concat fun answer = answer.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">".apply(<span class="hljs-subst">#{ref}</span>, "</span>), splatArgs, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">")"</span>)</pre></div></div> </li> <li id="section-61"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-61">¶</a> </div> <h3 id="extends">Extends</h3> </div> </li> <li id="section-62"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-62">¶</a> </div> <p>Node to extend an object’s 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><span class="hljs-built_in">exports</span>.Extends = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Extends</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@child</span>, <span class="hljs-property">@parent</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'child'</span>, <span class="hljs-string">'parent'</span>]</pre></div></div> </li> <li id="section-63"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-63">¶</a> </div> <p>Hooks one constructor into another’s prototype chain.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></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), [<span class="hljs-property">@child</span>, <span class="hljs-property">@parent</span>]).compileToFragments o</pre></div></div> </li> <li id="section-64"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-64">¶</a> </div> <h3 id="access">Access</h3> </div> </li> <li id="section-65"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-65">¶</a> </div> <p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for an access into the object’s prototype.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Access = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Access</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@name</span>, tag)</span> -></span> <span class="hljs-property">@name</span>.asKey = <span class="hljs-literal">yes</span> <span class="hljs-property">@soak</span> = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'soak'</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'name'</span>] <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> name = <span class="hljs-property">@name</span>.compileToFragments o <span class="hljs-keyword">if</span> IDENTIFIER.test fragmentsToText name name.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"."</span> <span class="hljs-keyword">else</span> name.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"["</span> name.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"]"</span> name <span class="hljs-attribute">isComplex</span>: NO</pre></div></div> </li> <li id="section-66"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-66">¶</a> </div> <h3 id="index">Index</h3> </div> </li> <li id="section-67"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-67">¶</a> </div> <p>A <code>[ ... ]</code> indexed access into an array or object.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Index = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@index</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'index'</span>] <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"["</span>), <span class="hljs-property">@index</span>.compileToFragments(o, LEVEL_PAREN), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"]"</span>) <span class="hljs-attribute">isComplex</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@index</span>.isComplex()</pre></div></div> </li> <li id="section-68"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-68">¶</a> </div> <h3 id="range">Range</h3> </div> </li> <li id="section-69"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-69">¶</a> </div> <p>A range literal. Ranges can be used to extract portions (slices) of arrays, to specify a range for comprehensions, or as a value, to be expanded into the corresponding array of integers at runtime.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Range = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Range</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'from'</span>, <span class="hljs-string">'to'</span>] <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@from</span>, <span class="hljs-property">@to</span>, tag)</span> -></span> <span class="hljs-property">@exclusive</span> = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'exclusive'</span> <span class="hljs-property">@equals</span> = <span class="hljs-keyword">if</span> <span class="hljs-property">@exclusive</span> <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'='</span></pre></div></div> </li> <li id="section-70"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-70">¶</a> </div> <p>Compiles the range’s source variables — where it starts and where it ends. But only if they need to be cached to avoid double evaluation.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileVariables</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o = merge o, <span class="hljs-attribute">top</span>: <span class="hljs-literal">true</span> isComplex = del o, <span class="hljs-string">'isComplex'</span> [<span class="hljs-property">@fromC</span>, <span class="hljs-property">@fromVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@from</span>.cache o, LEVEL_LIST, isComplex [<span class="hljs-property">@toC</span>, <span class="hljs-property">@toVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@to</span>.cache o, LEVEL_LIST, isComplex [<span class="hljs-property">@step</span>, <span class="hljs-property">@stepVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> step.cache o, LEVEL_LIST, isComplex <span class="hljs-keyword">if</span> step = del o, <span class="hljs-string">'step'</span> [<span class="hljs-property">@fromNum</span>, <span class="hljs-property">@toNum</span>] = [<span class="hljs-property">@fromVar</span>.match(NUMBER), <span class="hljs-property">@toVar</span>.match(NUMBER)] <span class="hljs-property">@stepNum</span> = <span class="hljs-property">@stepVar</span>.match(NUMBER) <span class="hljs-keyword">if</span> <span class="hljs-property">@stepVar</span></pre></div></div> </li> <li id="section-71"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-71">¶</a> </div> <p>When compiled normally, the range returns the contents of the <em>for loop</em> needed to iterate over the values in the range. Used by comprehensions.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@compileVariables</span> o <span class="hljs-keyword">unless</span> <span class="hljs-property">@fromVar</span> <span class="hljs-keyword">return</span> <span class="hljs-property">@compileArray</span>(o) <span class="hljs-keyword">unless</span> o.index</pre></div></div> </li> <li id="section-72"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-72">¶</a> </div> <p>Set up endpoints.</p> </div> <div class="content"><div class='highlight'><pre> known = <span class="hljs-property">@fromNum</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@toNum</span> idx = del o, <span class="hljs-string">'index'</span> idxName = del o, <span class="hljs-string">'name'</span> namedIndex = idxName <span class="hljs-keyword">and</span> idxName <span class="hljs-keyword">isnt</span> idx varPart = <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> = <span class="hljs-subst">#{<span class="hljs-property">@fromC</span>}</span>"</span> varPart += <span class="hljs-string">", <span class="hljs-subst">#{<span class="hljs-property">@toC</span>}</span>"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@toC</span> <span class="hljs-keyword">isnt</span> <span class="hljs-property">@toVar</span> varPart += <span class="hljs-string">", <span class="hljs-subst">#{<span class="hljs-property">@step</span>}</span>"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@step</span> <span class="hljs-keyword">isnt</span> <span class="hljs-property">@stepVar</span> [lt, gt] = [<span class="hljs-string">"<span class="hljs-subst">#{idx}</span> <<span class="hljs-subst">#{<span class="hljs-property">@equals</span>}</span>"</span>, <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> ><span class="hljs-subst">#{<span class="hljs-property">@equals</span>}</span>"</span>]</pre></div></div> </li> <li id="section-73"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-73">¶</a> </div> <p>Generate the condition.</p> </div> <div class="content"><div class='highlight'><pre> condPart = <span class="hljs-keyword">if</span> <span class="hljs-property">@stepNum</span> <span class="hljs-keyword">if</span> parseNum(<span class="hljs-property">@stepNum</span>[<span class="hljs-number">0</span>]) > <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">#{<span class="hljs-property">@toVar</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> known [from, to] = [parseNum(<span class="hljs-property">@fromNum</span>[<span class="hljs-number">0</span>]), parseNum(<span class="hljs-property">@toNum</span>[<span class="hljs-number">0</span>])] <span class="hljs-keyword">if</span> from <= to <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{to}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{to}</span>"</span> <span class="hljs-keyword">else</span> cond = <span class="hljs-keyword">if</span> <span class="hljs-property">@stepVar</span> <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@stepVar</span>}</span> > 0"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@fromVar</span>}</span> <= <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span>"</span> <span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{lt}</span> <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span> : <span class="hljs-subst">#{gt}</span> <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span>"</span></pre></div></div> </li> <li id="section-74"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-74">¶</a> </div> <p>Generate the step.</p> </div> <div class="content"><div class='highlight'><pre> stepPart = <span class="hljs-keyword">if</span> <span class="hljs-property">@stepVar</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span> += <span class="hljs-subst">#{<span class="hljs-property">@stepVar</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> known <span class="hljs-keyword">if</span> namedIndex <span class="hljs-keyword">if</span> from <= 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 <= to <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>++"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{idx}</span>--"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> namedIndex <span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? ++<span class="hljs-subst">#{idx}</span> : --<span class="hljs-subst">#{idx}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{idx}</span>++ : <span class="hljs-subst">#{idx}</span>--"</span> varPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{varPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex stepPart = <span class="hljs-string">"<span class="hljs-subst">#{idxName}</span> = <span class="hljs-subst">#{stepPart}</span>"</span> <span class="hljs-keyword">if</span> namedIndex</pre></div></div> </li> <li id="section-75"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-75">¶</a> </div> <p>The final loop body.</p> </div> <div class="content"><div class='highlight'><pre> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"<span class="hljs-subst">#{varPart}</span>; <span class="hljs-subst">#{condPart}</span>; <span class="hljs-subst">#{stepPart}</span>"</span>]</pre></div></div> </li> <li id="section-76"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-76">¶</a> </div> <p>When used as a value, expand the range into the equivalent array.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileArray</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@fromNum</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@toNum</span> <span class="hljs-keyword">and</span> Math.abs(<span class="hljs-property">@fromNum</span> - <span class="hljs-property">@toNum</span>) <= <span class="hljs-number">20</span> range = [+<span class="hljs-property">@fromNum</span>..+<span class="hljs-property">@toNum</span>] range.pop() <span class="hljs-keyword">if</span> <span class="hljs-property">@exclusive</span> <span class="hljs-keyword">return</span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"[<span class="hljs-subst">#{ range.join(<span class="hljs-string">', '</span>) }</span>]"</span>] idt = <span class="hljs-property">@tab</span> + TAB i = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span> result = o.scope.freeVariable <span class="hljs-string">'results'</span> pre = <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{result}</span> = [];"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@fromNum</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@toNum</span> o.index = i body = fragmentsToText <span class="hljs-property">@compileNode</span> o <span class="hljs-keyword">else</span> vars = <span class="hljs-string">"<span class="hljs-subst">#{i}</span> = <span class="hljs-subst">#{<span class="hljs-property">@fromC</span>}</span>"</span> + <span class="hljs-keyword">if</span> <span class="hljs-property">@toC</span> <span class="hljs-keyword">isnt</span> <span class="hljs-property">@toVar</span> <span class="hljs-keyword">then</span> <span class="hljs-string">", <span class="hljs-subst">#{<span class="hljs-property">@toC</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span> cond = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@fromVar</span>}</span> <= <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</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> <<span class="hljs-subst">#{<span class="hljs-property">@equals</span>}</span> <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span> : <span class="hljs-subst">#{i}</span> ><span class="hljs-subst">#{<span class="hljs-property">@equals</span>}</span> <span class="hljs-subst">#{<span class="hljs-property">@toVar</span>}</span>; <span class="hljs-subst">#{cond}</span> ? <span class="hljs-subst">#{i}</span>++ : <span class="hljs-subst">#{i}</span>--"</span> post = <span class="hljs-string">"{ <span class="hljs-subst">#{result}</span>.push(<span class="hljs-subst">#{i}</span>); }\n<span class="hljs-subst">#{idt}</span>return <span class="hljs-subst">#{result}</span>;\n<span class="hljs-subst">#{o.indent}</span>"</span> <span class="hljs-function"><span class="hljs-title">hasArgs</span> = <span class="hljs-params">(node)</span> -></span> node?.contains isLiteralArguments args = <span class="hljs-string">', arguments'</span> <span class="hljs-keyword">if</span> hasArgs(<span class="hljs-property">@from</span>) <span class="hljs-keyword">or</span> hasArgs(<span class="hljs-property">@to</span>) [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"(function() {<span class="hljs-subst">#{pre}</span>\n<span class="hljs-subst">#{idt}</span>for (<span class="hljs-subst">#{body}</span>)<span class="hljs-subst">#{post}</span>}).apply(this<span class="hljs-subst">#{args ? <span class="hljs-string">''</span>}</span>)"</span>]</pre></div></div> </li> <li id="section-77"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-77">¶</a> </div> <h3 id="slice">Slice</h3> </div> </li> <li id="section-78"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-78">¶</a> </div> <p>An array slice literal. Unlike JavaScript’s <code>Array#slice</code>, the second parameter specifies the index of the end of the slice, just as the first parameter is the index of the beginning.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Slice = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Slice</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'range'</span>] <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@range</span>)</span> -></span> <span class="hljs-keyword">super</span>()</pre></div></div> </li> <li id="section-79"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-79">¶</a> </div> <p>We have to be careful when trying to slice through the end of the array, <code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>. <code>9e9</code> should be safe because <code>9e9</code> > <code>2**32</code>, the max array length.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> {to, from} = <span class="hljs-property">@range</span> fromCompiled = from <span class="hljs-keyword">and</span> from.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">or</span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">'0'</span>]</pre></div></div> </li> <li id="section-80"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-80">¶</a> </div> <p>TODO: jwalton - move this into the ‘if’?</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> to compiled = to.compileToFragments o, LEVEL_PAREN compiledText = fragmentsToText compiled <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">not</span> <span class="hljs-property">@range</span>.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> <span class="hljs-property">@range</span>.exclusive compiledText <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> SIMPLENUM.test compiledText <span class="hljs-string">"<span class="hljs-subst">#{+compiledText + <span class="hljs-number">1</span>}</span>"</span> <span class="hljs-keyword">else</span> compiled = to.compileToFragments o, LEVEL_ACCESS <span class="hljs-string">"+<span class="hljs-subst">#{fragmentsToText compiled}</span> + 1 || 9e9"</span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">".slice(<span class="hljs-subst">#{ fragmentsToText fromCompiled }</span><span class="hljs-subst">#{ toStr <span class="hljs-keyword">or</span> <span class="hljs-string">''</span> }</span>)"</span>]</pre></div></div> </li> <li id="section-81"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-81">¶</a> </div> <h3 id="obj">Obj</h3> </div> </li> <li id="section-82"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-82">¶</a> </div> <p>An object literal, nothing fancy.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Obj = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Obj</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(props, <span class="hljs-property">@generated</span> = <span class="hljs-literal">false</span>)</span> -></span> <span class="hljs-property">@objects</span> = <span class="hljs-property">@properties</span> = props <span class="hljs-keyword">or</span> [] <span class="hljs-attribute">children</span>: [<span class="hljs-string">'properties'</span>] <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> props = <span class="hljs-property">@properties</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@generated</span> <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> <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 < props.length idt = o.indent += TAB lastNoncom = <span class="hljs-property">@lastNonComment</span> <span class="hljs-property">@properties</span> answer = [] <span class="hljs-keyword">if</span> hasDynamic oref = o.scope.freeVariable <span class="hljs-string">'obj'</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"(\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span> = "</span> answer.push <span class="hljs-property">@makeCode</span> <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> <span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> dynamicIndex answer.push <span class="hljs-property">@makeCode</span> <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 <span class="hljs-property">@makeCode</span> <span class="hljs-string">',\n'</span> join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> i <span class="hljs-keyword">is</span> dynamicIndex - <span class="hljs-number">1</span> <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 indent += TAB <span class="hljs-keyword">if</span> hasDynamic <span class="hljs-keyword">and</span> i < dynamicIndex <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> <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 <span class="hljs-keyword">if</span> i < 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 prop = <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal 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 <span class="hljs-property">@makeCode</span> indent answer.push prop.compileToFragments(o, LEVEL_TOP)... <span class="hljs-keyword">if</span> join <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> join <span class="hljs-keyword">if</span> hasDynamic answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">",\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span>\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>)"</span> <span class="hljs-keyword">else</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</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> <span class="hljs-property">@front</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> hasDynamic <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer <span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> <span class="hljs-property">@properties</span> <span class="hljs-keyword">when</span> prop.assigns name <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-literal">no</span></pre></div></div> </li> <li id="section-83"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-83">¶</a> </div> <h3 id="arr">Arr</h3> </div> </li> <li id="section-84"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-84">¶</a> </div> <p>An array literal.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Arr = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Arr</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(objs)</span> -></span> <span class="hljs-property">@objects</span> = objs <span class="hljs-keyword">or</span> [] <span class="hljs-attribute">children</span>: [<span class="hljs-string">'objects'</span>] <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">return</span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">'[]'</span>] <span class="hljs-keyword">unless</span> <span class="hljs-property">@objects</span>.length o.indent += TAB answer = Splat.compileSplattedArray o, <span class="hljs-property">@objects</span> <span class="hljs-keyword">return</span> answer <span class="hljs-keyword">if</span> answer.length answer = [] compiledObjs = (obj.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> <span class="hljs-property">@objects</span>) <span class="hljs-keyword">for</span> fragments, index <span class="hljs-keyword">in</span> compiledObjs <span class="hljs-keyword">if</span> index answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">", "</span> answer.push fragments... <span class="hljs-keyword">if</span> fragmentsToText(answer).indexOf(<span class="hljs-string">'\n'</span>) >= <span class="hljs-number">0</span> answer.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"[\n<span class="hljs-subst">#{o.indent}</span>"</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>]"</span> <span class="hljs-keyword">else</span> answer.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"["</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"]"</span> answer <span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> <span class="hljs-property">@objects</span> <span class="hljs-keyword">when</span> obj.assigns name <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-literal">no</span></pre></div></div> </li> <li id="section-85"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-85">¶</a> </div> <h3 id="class">Class</h3> </div> </li> <li id="section-86"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-86">¶</a> </div> <p>The CoffeeScript class definition. Initialize a <strong>Class</strong> with its name, an optional superclass, and a list of prototype property assignments.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Class = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@variable</span>, <span class="hljs-property">@parent</span>, <span class="hljs-property">@body</span> = <span class="hljs-keyword">new</span> Block)</span> -></span> <span class="hljs-property">@boundFuncs</span> = [] <span class="hljs-property">@body</span>.classBody = <span class="hljs-literal">yes</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'parent'</span>, <span class="hljs-string">'body'</span>]</pre></div></div> </li> <li id="section-87"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-87">¶</a> </div> <p>Figure out the appropriate name for the constructor function of this class.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">determineName</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@variable</span> [..., tail] = <span class="hljs-property">@variable</span>.properties decl = <span class="hljs-keyword">if</span> tail tail <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> tail.name.value <span class="hljs-keyword">else</span> <span class="hljs-property">@variable</span>.base.value <span class="hljs-keyword">if</span> decl <span class="hljs-keyword">in</span> STRICT_PROSCRIBED <span class="hljs-property">@variable</span>.error <span class="hljs-string">"class variable name may not be <span class="hljs-subst">#{decl}</span>"</span> decl <span class="hljs-keyword">and</span>= IDENTIFIER.test(decl) <span class="hljs-keyword">and</span> decl</pre></div></div> </li> <li id="section-88"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-88">¶</a> </div> <p>For all <code>this</code>-references and bound functions in the class definition, <code>this</code> is the Class being constructed.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">setContext</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-property">@body</span>.traverseChildren <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span> <span class="hljs-keyword">if</span> node.classBody <span class="hljs-keyword">if</span> 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">'this'</span> node.value = name <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> <li id="section-89"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-89">¶</a> </div> <p>Ensure that all functions bound to the instance are proxied in the constructor.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">addBoundFunctions</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">for</span> bvar <span class="hljs-keyword">in</span> <span class="hljs-property">@boundFuncs</span> lhs = (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal <span class="hljs-string">"this"</span>), [<span class="hljs-keyword">new</span> Access bvar]).compile o <span class="hljs-property">@ctor</span>.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> <span class="hljs-keyword">return</span></pre></div></div> </li> <li id="section-90"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-90">¶</a> </div> <p>Merge the properties from a top-level object as prototypal properties on the class.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">addProperties</span>: <span class="hljs-function"><span class="hljs-params">(node, name, o)</span> -></span> props = node.base.properties[..] exprs = <span class="hljs-keyword">while</span> assign = props.shift() <span class="hljs-keyword">if</span> assign <span class="hljs-keyword">instanceof</span> Assign base = assign.variable.base <span class="hljs-keyword">delete</span> assign.context func = assign.value <span class="hljs-keyword">if</span> base.value <span class="hljs-keyword">is</span> <span class="hljs-string">'constructor'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@ctor</span> 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 assign = <span class="hljs-property">@ctor</span> = func <span class="hljs-keyword">else</span> <span class="hljs-property">@externalCtor</span> = o.classScope.freeVariable <span class="hljs-string">'class'</span> assign = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Literal(<span class="hljs-property">@externalCtor</span>), func <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> 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 assign.variable = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal(name), [(<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'prototype'</span>), acc]) <span class="hljs-keyword">if</span> func <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> func.bound <span class="hljs-property">@boundFuncs</span>.push base func.bound = <span class="hljs-literal">no</span> assign compact exprs</pre></div></div> </li> <li id="section-91"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-91">¶</a> </div> <p>Walk the body of the class, looking for prototype properties to be converted and tagging static assignments.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">walkBody</span>: <span class="hljs-function"><span class="hljs-params">(name, o)</span> -></span> <span class="hljs-property">@traverseChildren</span> <span class="hljs-literal">false</span>, <span class="hljs-function"><span class="hljs-params">(child)</span> =></span> 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> exps[i] = <span class="hljs-property">@addProperties</span> node, name, o child.expressions = exps = flatten exps 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> <li id="section-92"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-92">¶</a> </div> <p><code>use strict</code> (and other directives) must be the first expression statement(s) of a function body. This method ensures the prologue is correctly positioned above the <code>constructor</code>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">hoistDirectivePrologue</span>:<span class="hljs-function"> -></span> index = <span class="hljs-number">0</span> {expressions} = <span class="hljs-property">@body</span> ++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() <span class="hljs-property">@directives</span> = expressions.splice <span class="hljs-number">0</span>, index</pre></div></div> </li> <li id="section-93"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-93">¶</a> </div> <p>Make sure that a constructor is defined for the class, and properly configured.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">ensureConstructor</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@ctor</span> <span class="hljs-property">@ctor</span> = <span class="hljs-keyword">new</span> Code <span class="hljs-keyword">if</span> <span class="hljs-property">@externalCtor</span> <span class="hljs-property">@ctor</span>.body.push <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@externalCtor</span>}</span>.apply(this, arguments)"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@parent</span> <span class="hljs-property">@ctor</span>.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> <span class="hljs-property">@ctor</span>.body.makeReturn() <span class="hljs-property">@body</span>.expressions.unshift <span class="hljs-property">@ctor</span> <span class="hljs-property">@ctor</span>.ctor = <span class="hljs-property">@ctor</span>.name = name <span class="hljs-property">@ctor</span>.klass = <span class="hljs-literal">null</span> <span class="hljs-property">@ctor</span>.noReturn = <span class="hljs-literal">yes</span></pre></div></div> </li> <li id="section-94"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-94">¶</a> </div> <p>Instead of generating the JavaScript string directly, we build up the equivalent syntax tree and compile that, in pieces. You can see the constructor, property assignments, and inheritance getting built out below.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> jumpNode = <span class="hljs-property">@body</span>.jumps() jumpNode.error <span class="hljs-string">'Class bodies cannot contain pure statements'</span> <span class="hljs-keyword">if</span> argumentsNode = <span class="hljs-property">@body</span>.contains isLiteralArguments argumentsNode.error <span class="hljs-string">"Class bodies shouldn't reference arguments"</span> name = <span class="hljs-property">@determineName</span>() <span class="hljs-keyword">or</span> <span class="hljs-string">'_Class'</span> name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name.reserved lname = <span class="hljs-keyword">new</span> Literal name func = <span class="hljs-keyword">new</span> Code [], Block.wrap [<span class="hljs-property">@body</span>] args = [] o.classScope = func.makeScope o.scope <span class="hljs-property">@hoistDirectivePrologue</span>() <span class="hljs-property">@setContext</span> name <span class="hljs-property">@walkBody</span> name, o <span class="hljs-property">@ensureConstructor</span> name <span class="hljs-property">@addBoundFunctions</span> o <span class="hljs-property">@body</span>.spaced = <span class="hljs-literal">yes</span> <span class="hljs-property">@body</span>.expressions.push lname <span class="hljs-keyword">if</span> <span class="hljs-property">@parent</span> superClass = <span class="hljs-keyword">new</span> Literal o.classScope.freeVariable <span class="hljs-string">'superClass'</span>, <span class="hljs-attribute">reserve</span>: <span class="hljs-literal">no</span> <span class="hljs-property">@body</span>.expressions.unshift <span class="hljs-keyword">new</span> Extends lname, superClass func.params.push <span class="hljs-keyword">new</span> Param superClass args.push <span class="hljs-property">@parent</span> <span class="hljs-property">@body</span>.expressions.unshift <span class="hljs-property">@directives</span>... klass = <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Call func, args klass = <span class="hljs-keyword">new</span> Assign <span class="hljs-property">@variable</span>, klass <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span> klass.compileToFragments o</pre></div></div> </li> <li id="section-95"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-95">¶</a> </div> <h3 id="assign">Assign</h3> </div> </li> <li id="section-96"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-96">¶</a> </div> <p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the property of an object — including within object literals.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Assign = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Assign</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@variable</span>, <span class="hljs-property">@value</span>, <span class="hljs-property">@context</span>, options = {})</span> -></span> {<span class="hljs-property">@param</span>, <span class="hljs-property">@subpattern</span>, <span class="hljs-property">@operatorToken</span>} = options forbidden = (name = <span class="hljs-property">@variable</span>.unwrapAll().value) <span class="hljs-keyword">in</span> STRICT_PROSCRIBED <span class="hljs-keyword">if</span> forbidden <span class="hljs-keyword">and</span> <span class="hljs-property">@context</span> <span class="hljs-keyword">isnt</span> <span class="hljs-string">'object'</span> <span class="hljs-property">@variable</span>.error <span class="hljs-string">"variable name may not be \"<span class="hljs-subst">#{name}</span>\""</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'variable'</span>, <span class="hljs-string">'value'</span>] <span class="hljs-attribute">isStatement</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">and</span> <span class="hljs-property">@context</span>? <span class="hljs-keyword">and</span> <span class="hljs-string">"?"</span> <span class="hljs-keyword">in</span> <span class="hljs-property">@context</span> <span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> @[<span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <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 <span class="hljs-attribute">unfoldSoak</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> unfoldSoak o, <span class="hljs-keyword">this</span>, <span class="hljs-string">'variable'</span></pre></div></div> </li> <li id="section-97"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-97">¶</a> </div> <p>Compile an assignment, delegating to <code>compilePatternMatch</code> or <code>compileSplice</code> if appropriate. Keep track of the name of the base object we’ve been assigned to, for correct internal references. If the variable has not been seen yet within the current scope, declare it.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> isValue = <span class="hljs-property">@variable</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">return</span> <span class="hljs-property">@compilePatternMatch</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span>.isArray() <span class="hljs-keyword">or</span> <span class="hljs-property">@variable</span>.isObject() <span class="hljs-keyword">return</span> <span class="hljs-property">@compileSplice</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span>.isSplice() <span class="hljs-keyword">return</span> <span class="hljs-property">@compileConditional</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <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">return</span> <span class="hljs-property">@compileSpecialMath</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <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> <span class="hljs-property">@value</span> <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span>.static <span class="hljs-property">@value</span>.klass = <span class="hljs-property">@variable</span>.base <span class="hljs-property">@value</span>.name = <span class="hljs-property">@variable</span>.properties[<span class="hljs-number">0</span>] <span class="hljs-property">@value</span>.variable = <span class="hljs-property">@variable</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span>.properties?.length >= <span class="hljs-number">2</span> [properties..., prototype, name] = <span class="hljs-property">@variable</span>.properties <span class="hljs-keyword">if</span> prototype.name?.value <span class="hljs-keyword">is</span> <span class="hljs-string">'prototype'</span> <span class="hljs-property">@value</span>.klass = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@variable</span>.base, properties <span class="hljs-property">@value</span>.name = name <span class="hljs-property">@value</span>.variable = <span class="hljs-property">@variable</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@context</span> varBase = <span class="hljs-property">@variable</span>.unwrapAll() <span class="hljs-keyword">unless</span> varBase.isAssignable() <span class="hljs-property">@variable</span>.error <span class="hljs-string">"\"<span class="hljs-subst">#{<span class="hljs-property">@variable</span>.compile o}</span>\" cannot be assigned"</span> <span class="hljs-keyword">unless</span> varBase.hasProperties?() <span class="hljs-keyword">if</span> <span class="hljs-property">@param</span> o.scope.add varBase.value, <span class="hljs-string">'var'</span> <span class="hljs-keyword">else</span> o.scope.find varBase.value val = <span class="hljs-property">@value</span>.compileToFragments o, LEVEL_LIST <span class="hljs-property">@variable</span>.front = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> isValue <span class="hljs-keyword">and</span> <span class="hljs-property">@variable</span>.base <span class="hljs-keyword">instanceof</span> Obj compiledName = <span class="hljs-property">@variable</span>.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">return</span> (compiledName.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">": "</span>), val) <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span> answer = compiledName.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" <span class="hljs-subst">#{ <span class="hljs-property">@context</span> <span class="hljs-keyword">or</span> <span class="hljs-string">'='</span> }</span> "</span>), val <span class="hljs-keyword">if</span> o.level <= LEVEL_LIST <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> answer</pre></div></div> </li> <li id="section-98"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-98">¶</a> </div> <p>Brief implementation of recursive pattern matching, when assigning array or object literals to a value. Peeks at their properties to assign inner names.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compilePatternMatch</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> top = o.level <span class="hljs-keyword">is</span> LEVEL_TOP {value} = <span class="hljs-keyword">this</span> {objects} = <span class="hljs-property">@variable</span>.base <span class="hljs-keyword">unless</span> olen = objects.length code = value.compileToFragments o <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> o.level >= LEVEL_OP <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> code <span class="hljs-keyword">else</span> code [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> isObject = <span class="hljs-property">@variable</span>.isObject() <span class="hljs-keyword">if</span> top <span class="hljs-keyword">and</span> olen <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Splat</pre></div></div> </li> <li id="section-99"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-99">¶</a> </div> <p>Pick the property straight off the value when there’s just one to pick (no need to cache the value into a variable).</p> </div> <div class="content"><div class='highlight'><pre> defaultValue = <span class="hljs-literal">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> <li id="section-100"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-100">¶</a> </div> <p>A regular object pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> {<span class="hljs-attribute">variable</span>: {<span class="hljs-attribute">base</span>: idx}, <span class="hljs-attribute">value</span>: obj} = obj <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign defaultValue = obj.value obj = obj.variable <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign defaultValue = obj.value obj = obj.variable idx = <span class="hljs-keyword">if</span> isObject</pre></div></div> </li> <li id="section-101"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-101">¶</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span> <span class="hljs-keyword">then</span> obj.properties[<span class="hljs-number">0</span>].name <span class="hljs-keyword">else</span> obj <span class="hljs-keyword">else</span></pre></div></div> </li> <li id="section-102"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-102">¶</a> </div> <p>A regular array pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> Literal <span class="hljs-number">0</span> acc = IDENTIFIER.test idx.unwrap().value 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 <span class="hljs-keyword">if</span> obj.unwrap().value <span class="hljs-keyword">in</span> RESERVED obj.error <span class="hljs-string">"assignment to a reserved word: <span class="hljs-subst">#{obj.compile o}</span>"</span> value = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, value, defaultValue <span class="hljs-keyword">if</span> defaultValue <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Assign(obj, value, <span class="hljs-literal">null</span>, <span class="hljs-attribute">param</span>: <span class="hljs-property">@param</span>).compileToFragments o, LEVEL_TOP vvar = value.compileToFragments o, LEVEL_LIST vvarText = fragmentsToText vvar assigns = [] expandedIdx = <span class="hljs-literal">false</span></pre></div></div> </li> <li id="section-103"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-103">¶</a> </div> <p>Make vvar into a simple variable if it isn’t already.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> IDENTIFIER.test(vvarText) <span class="hljs-keyword">or</span> <span class="hljs-property">@variable</span>.assigns(vvarText) assigns.push [<span class="hljs-property">@makeCode</span>(<span class="hljs-string">"<span class="hljs-subst">#{ ref = o.scope.freeVariable <span class="hljs-string">'ref'</span> }</span> = "</span>), vvar...] vvar = [<span class="hljs-property">@makeCode</span> ref] vvarText = ref <span class="hljs-keyword">for</span> obj, i <span class="hljs-keyword">in</span> objects idx = i <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Splat name = obj.name.unwrap().value obj = obj.unwrap() val = <span class="hljs-string">"<span class="hljs-subst">#{olen}</span> <= <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> <span class="hljs-keyword">if</span> rest = olen - i - <span class="hljs-number">1</span> ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span> val += <span class="hljs-string">", <span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>) : (<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{i}</span>, [])"</span> <span class="hljs-keyword">else</span> val += <span class="hljs-string">") : []"</span> val = <span class="hljs-keyword">new</span> Literal val expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Expansion <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> ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span> val = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>"</span> expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span> assigns.push val.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">continue</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat <span class="hljs-keyword">or</span> obj <span class="hljs-keyword">instanceof</span> Expansion obj.error <span class="hljs-string">"multiple splats/expansions are disallowed in an assignment"</span> defaultValue = <span class="hljs-literal">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> <li id="section-104"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-104">¶</a> </div> <p>A regular object pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> {<span class="hljs-attribute">variable</span>: {<span class="hljs-attribute">base</span>: idx}, <span class="hljs-attribute">value</span>: obj} = obj <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign defaultValue = obj.value obj = obj.variable <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign defaultValue = obj.value obj = obj.variable idx = <span class="hljs-keyword">if</span> isObject</pre></div></div> </li> <li id="section-105"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-105">¶</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span> <span class="hljs-keyword">then</span> obj.properties[<span class="hljs-number">0</span>].name <span class="hljs-keyword">else</span> obj <span class="hljs-keyword">else</span></pre></div></div> </li> <li id="section-106"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-106">¶</a> </div> <p>A regular array pattern-match.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">new</span> Literal expandedIdx <span class="hljs-keyword">or</span> idx name = obj.unwrap().value acc = IDENTIFIER.test idx.unwrap().value 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] val = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, val, defaultValue <span class="hljs-keyword">if</span> defaultValue <span class="hljs-keyword">if</span> name? <span class="hljs-keyword">and</span> name <span class="hljs-keyword">in</span> RESERVED obj.error <span class="hljs-string">"assignment to a reserved word: <span class="hljs-subst">#{obj.compile o}</span>"</span> assigns.push <span class="hljs-keyword">new</span> Assign(obj, val, <span class="hljs-literal">null</span>, <span class="hljs-attribute">param</span>: <span class="hljs-property">@param</span>, <span class="hljs-attribute">subpattern</span>: <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> <span class="hljs-property">@subpattern</span> fragments = <span class="hljs-property">@joinFragmentArrays</span> assigns, <span class="hljs-string">', '</span> <span class="hljs-keyword">if</span> o.level < LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> fragments</pre></div></div> </li> <li id="section-107"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-107">¶</a> </div> <p>When compiling a conditional assignment, take care to ensure that the operands are only evaluated once, even though we have to reference them more than once.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileConditional</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [left, right] = <span class="hljs-property">@variable</span>.cacheReference o</pre></div></div> </li> <li id="section-108"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-108">¶</a> </div> <p>Disallow conditional assignment of undefined variables.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> left.properties.length <span class="hljs-keyword">and</span> left.base <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> left.base.value != <span class="hljs-string">"this"</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check left.base.value <span class="hljs-property">@variable</span>.error <span class="hljs-string">"the variable \"<span class="hljs-subst">#{left.base.value}</span>\" can't be assigned with <span class="hljs-subst">#{<span class="hljs-property">@context</span>}</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> <span class="hljs-property">@context</span> o.isExistentialEquals = <span class="hljs-literal">true</span> <span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(left), right, <span class="hljs-attribute">type</span>: <span class="hljs-string">'if'</span>).addElse(<span class="hljs-keyword">new</span> Assign(right, <span class="hljs-property">@value</span>, <span class="hljs-string">'='</span>)).compileToFragments o <span class="hljs-keyword">else</span> fragments = <span class="hljs-keyword">new</span> Op(<span class="hljs-property">@context</span>[...-<span class="hljs-number">1</span>], left, <span class="hljs-keyword">new</span> Assign(right, <span class="hljs-property">@value</span>, <span class="hljs-string">'='</span>)).compileToFragments o <span class="hljs-keyword">if</span> o.level <= LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> fragments</pre></div></div> </li> <li id="section-109"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-109">¶</a> </div> <p>Convert special math assignment operators like <code>a **= b</code> to the equivalent extended form <code>a = a ** b</code> and then compiles that.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileSpecialMath</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [left, right] = <span class="hljs-property">@variable</span>.cacheReference o <span class="hljs-keyword">new</span> Assign(left, <span class="hljs-keyword">new</span> Op(<span class="hljs-property">@context</span>[...-<span class="hljs-number">1</span>], right, <span class="hljs-property">@value</span>)).compileToFragments o</pre></div></div> </li> <li id="section-110"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-110">¶</a> </div> <p>Compile the assignment from an array splice literal, using JavaScript’s <code>Array#splice</code> method.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileSplice</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> {<span class="hljs-attribute">range</span>: {from, to, exclusive}} = <span class="hljs-property">@variable</span>.properties.pop() name = <span class="hljs-property">@variable</span>.compile o <span class="hljs-keyword">if</span> from [fromDecl, fromRef] = <span class="hljs-property">@cacheToCodeFragments</span> from.cache o, LEVEL_OP <span class="hljs-keyword">else</span> fromDecl = fromRef = <span class="hljs-string">'0'</span> <span class="hljs-keyword">if</span> to <span class="hljs-keyword">if</span> from <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> from.isSimpleNumber() <span class="hljs-keyword">and</span> to <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> to.isSimpleNumber() to = to.compile(o) - fromRef to += <span class="hljs-number">1</span> <span class="hljs-keyword">unless</span> exclusive <span class="hljs-keyword">else</span> to = to.compile(o, LEVEL_ACCESS) + <span class="hljs-string">' - '</span> + fromRef to += <span class="hljs-string">' + 1'</span> <span class="hljs-keyword">unless</span> exclusive <span class="hljs-keyword">else</span> to = <span class="hljs-string">"9e9"</span> [valDef, valRef] = <span class="hljs-property">@value</span>.cache o, LEVEL_LIST answer = [].concat <span class="hljs-property">@makeCode</span>(<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, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">")), "</span>), valRef <span class="hljs-keyword">if</span> o.level > LEVEL_TOP <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer</pre></div></div> </li> <li id="section-111"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-111">¶</a> </div> <h3 id="code">Code</h3> </div> </li> <li id="section-112"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-112">¶</a> </div> <p>A function definition. This is the only node that creates a new Scope. When for the purposes of walking the contents of a function body, the Code has no <em>children</em> — they’re within the inner scope.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Code = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(params, body, tag)</span> -></span> <span class="hljs-property">@params</span> = params <span class="hljs-keyword">or</span> [] <span class="hljs-property">@body</span> = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block <span class="hljs-property">@bound</span> = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'boundfunc'</span> <span class="hljs-property">@isGenerator</span> = !!<span class="hljs-property">@body</span>.contains <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>] <span class="hljs-attribute">children</span>: [<span class="hljs-string">'params'</span>, <span class="hljs-string">'body'</span>] <span class="hljs-attribute">isStatement</span>:<span class="hljs-function"> -></span> !!<span class="hljs-property">@ctor</span> <span class="hljs-attribute">jumps</span>: NO <span class="hljs-attribute">makeScope</span>: <span class="hljs-function"><span class="hljs-params">(parentScope)</span> -></span> <span class="hljs-keyword">new</span> Scope parentScope, <span class="hljs-property">@body</span>, <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-113"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-113">¶</a> </div> <p>Compilation creates a new scope unless explicitly asked to share with the outer scope. Handles splat parameters in the parameter list by peeking at the JavaScript <code>arguments</code> object. If the function is bound with the <code>=></code> arrow, generates a wrapper that saves the current value of <code>this</code> through a closure.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@bound</span> <span class="hljs-keyword">and</span> o.scope.method?.bound <span class="hljs-property">@context</span> = o.scope.method.context</pre></div></div> </li> <li id="section-114"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-114">¶</a> </div> <p>Handle bound functions early.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-property">@bound</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@context</span> <span class="hljs-property">@context</span> = <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> Literal <span class="hljs-property">@context</span>], <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> Literal <span class="hljs-string">'this'</span>]) boundfunc.updateLocationDataIfMissing <span class="hljs-property">@locationData</span> <span class="hljs-keyword">return</span> boundfunc.compileNode(o) o.scope = del(o, <span class="hljs-string">'classScope'</span>) <span class="hljs-keyword">or</span> <span class="hljs-property">@makeScope</span> o.scope o.scope.shared = del(o, <span class="hljs-string">'sharedScope'</span>) o.indent += TAB <span class="hljs-keyword">delete</span> o.bare <span class="hljs-keyword">delete</span> o.isExistentialEquals params = [] exprs = [] <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">when</span> param <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion o.scope.parameter param.asReference o <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <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> <span class="hljs-property">@params</span> <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 o.scope.add p.name.value, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span> 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> <span class="hljs-property">@params</span>)), <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'arguments'</span> <span class="hljs-keyword">break</span> <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">if</span> param.isComplex() val = ref = param.asReference o val = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'?'</span>, ref, param.value <span class="hljs-keyword">if</span> param.value exprs.push <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(param.name), val, <span class="hljs-string">'='</span>, <span class="hljs-attribute">param</span>: <span class="hljs-literal">yes</span> <span class="hljs-keyword">else</span> ref = param <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 wasEmpty = <span class="hljs-property">@body</span>.isEmpty() exprs.unshift splats <span class="hljs-keyword">if</span> splats <span class="hljs-property">@body</span>.expressions.unshift exprs... <span class="hljs-keyword">if</span> exprs.length <span class="hljs-keyword">for</span> p, i <span class="hljs-keyword">in</span> params params[i] = p.compileToFragments o o.scope.parameter fragmentsToText params[i] uniqs = [] <span class="hljs-property">@eachParamName</span> <span class="hljs-function"><span class="hljs-params">(name, node)</span> -></span> 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 uniqs.push name <span class="hljs-property">@body</span>.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> <span class="hljs-property">@noReturn</span> code = <span class="hljs-string">'function'</span> code += <span class="hljs-string">'*'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isGenerator</span> code += <span class="hljs-string">' '</span> + <span class="hljs-property">@name</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@ctor</span> code += <span class="hljs-string">'('</span> answer = [<span class="hljs-property">@makeCode</span>(code)] <span class="hljs-keyword">for</span> p, i <span class="hljs-keyword">in</span> params <span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">", "</span> answer.push p... answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">') {'</span> answer = answer.concat(<span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), <span class="hljs-property">@body</span>.compileWithDeclarations(o), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>"</span>)) <span class="hljs-keyword">unless</span> <span class="hljs-property">@body</span>.isEmpty() answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">'}'</span> <span class="hljs-keyword">return</span> [<span class="hljs-property">@makeCode</span>(<span class="hljs-property">@tab</span>), answer...] <span class="hljs-keyword">if</span> <span class="hljs-property">@ctor</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@front</span> <span class="hljs-keyword">or</span> (o.level >= LEVEL_ACCESS) <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer <span class="hljs-attribute">eachParamName</span>: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -></span> param.eachName iterator <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span></pre></div></div> </li> <li id="section-115"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-115">¶</a> </div> <p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries unless <code>crossScope</code> is <code>true</code>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">traverseChildren</span>: <span class="hljs-function"><span class="hljs-params">(crossScope, func)</span> -></span> <span class="hljs-keyword">super</span>(crossScope, func) <span class="hljs-keyword">if</span> crossScope</pre></div></div> </li> <li id="section-116"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-116">¶</a> </div> <h3 id="param">Param</h3> </div> </li> <li id="section-117"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-117">¶</a> </div> <p>A parameter in a function definition. Beyond a typical Javascript parameter, these parameters can also attach themselves to the context of the function, as well as be a splat, gathering up a group of parameters into an array.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Param = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Param</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@name</span>, <span class="hljs-property">@value</span>, <span class="hljs-property">@splat</span>)</span> -></span> <span class="hljs-keyword">if</span> (name = <span class="hljs-property">@name</span>.unwrapAll().value) <span class="hljs-keyword">in</span> STRICT_PROSCRIBED <span class="hljs-property">@name</span>.error <span class="hljs-string">"parameter name \"<span class="hljs-subst">#{name}</span>\" is not allowed"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@name</span> <span class="hljs-keyword">instanceof</span> Obj <span class="hljs-keyword">and</span> <span class="hljs-property">@name</span>.generated token = <span class="hljs-property">@name</span>.objects[<span class="hljs-number">0</span>].operatorToken token.error <span class="hljs-string">"unexpected <span class="hljs-subst">#{token.value}</span>"</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'name'</span>, <span class="hljs-string">'value'</span>] <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@name</span>.compileToFragments o, LEVEL_LIST <span class="hljs-attribute">asReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-property">@reference</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@reference</span> node = <span class="hljs-property">@name</span> <span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span> name = node.properties[<span class="hljs-number">0</span>].name.value name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name.reserved node = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable name <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.isComplex() node = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'arg'</span> node = <span class="hljs-keyword">new</span> Value node node = <span class="hljs-keyword">new</span> Splat node <span class="hljs-keyword">if</span> <span class="hljs-property">@splat</span> node.updateLocationDataIfMissing <span class="hljs-property">@locationData</span> <span class="hljs-property">@reference</span> = node <span class="hljs-attribute">isComplex</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@name</span>.isComplex()</pre></div></div> </li> <li id="section-118"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-118">¶</a> </div> <p>Iterates the name or names of a <code>Param</code>. In a sense, a destructured parameter represents multiple JS parameters. This method allows to iterate them all. The <code>iterator</code> function will be called as <code>iterator(name, node)</code> where <code>name</code> is the name of the parameter and <code>node</code> is the AST node corresponding to that name.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">eachName</span>: <span class="hljs-function"><span class="hljs-params">(iterator, name = <span class="hljs-property">@name</span>)</span>-></span> <span class="hljs-function"><span class="hljs-title">atParam</span> = <span class="hljs-params">(obj)</span> -></span> iterator <span class="hljs-string">"@<span class="hljs-subst">#{obj.properties[<span class="hljs-number">0</span>].name.value}</span>"</span>, obj</pre></div></div> </li> <li id="section-119"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-119">¶</a> </div> <ul> <li>simple literals <code>foo</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> iterator name.value, name <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Literal</pre></div></div> </li> <li id="section-120"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-120">¶</a> </div> <ul> <li>at-params <code>@foo</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> atParam name <span class="hljs-keyword">if</span> name <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> name.objects</pre></div></div> </li> <li id="section-121"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-121">¶</a> </div> <ul> <li>destructured parameter with default value</li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> obj.context? obj = obj.variable</pre></div></div> </li> <li id="section-122"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-122">¶</a> </div> <ul> <li>assignments within destructured parameters <code>{foo:bar}</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-property">@eachName</span> iterator, obj.value.unwrap()</pre></div></div> </li> <li id="section-123"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-123">¶</a> </div> <ul> <li>splats within destructured parameters <code>[xs...]</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Splat node = obj.name.unwrap() iterator node.value, node <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">instanceof</span> Value</pre></div></div> </li> <li id="section-124"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-124">¶</a> </div> <ul> <li>destructured parameters within destructured parameters <code>[{a}]</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> obj.isArray() <span class="hljs-keyword">or</span> obj.isObject() <span class="hljs-property">@eachName</span> iterator, obj.base</pre></div></div> </li> <li id="section-125"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-125">¶</a> </div> <ul> <li>at-params within destructured parameters <code>{@foo}</code></li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj.<span class="hljs-keyword">this</span> atParam obj</pre></div></div> </li> <li id="section-126"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-126">¶</a> </div> <ul> <li>simple destructured parameters {foo}</li> </ul> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> iterator obj.base.value, obj.base <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> obj <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion obj.error <span class="hljs-string">"illegal parameter <span class="hljs-subst">#{obj.compile()}</span>"</span> <span class="hljs-keyword">return</span></pre></div></div> </li> <li id="section-127"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-127">¶</a> </div> <h3 id="splat">Splat</h3> </div> </li> <li id="section-128"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-128">¶</a> </div> <p>A splat, either as a parameter to a function, an argument to a call, or as part of a destructuring assignment.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Splat = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Splat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'name'</span>] <span class="hljs-attribute">isAssignable</span>: YES <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-property">@name</span> = <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 <span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span> <span class="hljs-property">@name</span>.assigns name <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@name</span>.compileToFragments o <span class="hljs-attribute">unwrap</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@name</span></pre></div></div> </li> <li id="section-129"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-129">¶</a> </div> <p>Utility function that converts an arbitrary number of elements, mixed with splats, to a proper array.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-property">@compileSplattedArray</span>: <span class="hljs-function"><span class="hljs-params">(o, list, apply)</span> -></span> index = -<span class="hljs-number">1</span> <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 >= 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>] fragments = node.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> apply <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>) args = list[index..] <span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> args compiledNode = node.compileToFragments o, LEVEL_LIST args[i] = <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Splat <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>) <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> [..., 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> <li id="section-130"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-130">¶</a> </div> <h3 id="expansion">Expansion</h3> </div> </li> <li id="section-131"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-131">¶</a> </div> <p>Used to skip values inside an array destructuring (pattern matching) or parameter list.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Expansion = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expansion</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">isComplex</span>: NO <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@error</span> <span class="hljs-string">'Expansion must be used inside a destructuring assignment or parameter list'</span> <span class="hljs-attribute">asReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">this</span> <span class="hljs-attribute">eachName</span>: <span class="hljs-function"><span class="hljs-params">(iterator)</span> -></span></pre></div></div> </li> <li id="section-132"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-132">¶</a> </div> <h3 id="while">While</h3> </div> </li> <li id="section-133"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-133">¶</a> </div> <p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From it, all other loops can be manufactured. Useful in cases where you need more flexibility or more speed than a comprehension can provide.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.While = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">While</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(condition, options)</span> -></span> <span class="hljs-property">@condition</span> = <span class="hljs-keyword">if</span> options?.invert <span class="hljs-keyword">then</span> condition.invert() <span class="hljs-keyword">else</span> condition <span class="hljs-property">@guard</span> = options?.guard <span class="hljs-attribute">children</span>: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'body'</span>] <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> <span class="hljs-keyword">if</span> res <span class="hljs-keyword">super</span> <span class="hljs-keyword">else</span> <span class="hljs-property">@returns</span> = <span class="hljs-keyword">not</span> <span class="hljs-property">@jumps</span> <span class="hljs-attribute">loop</span>: <span class="hljs-literal">yes</span> <span class="hljs-keyword">this</span> <span class="hljs-attribute">addBody</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@body</span>)</span> -></span> <span class="hljs-keyword">this</span> <span class="hljs-attribute">jumps</span>:<span class="hljs-function"> -></span> {expressions} = <span class="hljs-property">@body</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">unless</span> expressions.length <span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> expressions <span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = node.jumps <span class="hljs-attribute">loop</span>: <span class="hljs-literal">yes</span> <span class="hljs-literal">no</span></pre></div></div> </li> <li id="section-134"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-134">¶</a> </div> <p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript <em>while</em> can be used as a part of a larger expression — while loops may return an array containing the computed result of each iteration.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o.indent += TAB set = <span class="hljs-string">''</span> {body} = <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> body.isEmpty() body = <span class="hljs-property">@makeCode</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@returns</span> body.makeReturn rvar = o.scope.freeVariable <span class="hljs-string">'results'</span> set = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@guard</span> <span class="hljs-keyword">if</span> body.expressions.length > <span class="hljs-number">1</span> body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens <span class="hljs-property">@guard</span>).invert(), <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"continue"</span> <span class="hljs-keyword">else</span> body = Block.wrap [<span class="hljs-keyword">new</span> If <span class="hljs-property">@guard</span>, body] <span class="hljs-keyword">if</span> <span class="hljs-property">@guard</span> body = [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), (body.compileToFragments o, LEVEL_TOP), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>"</span>) answer = [].concat <span class="hljs-property">@makeCode</span>(set + <span class="hljs-property">@tab</span> + <span class="hljs-string">"while ("</span>), <span class="hljs-property">@condition</span>.compileToFragments(o, LEVEL_PAREN), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") {"</span>), body, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"}"</span>) <span class="hljs-keyword">if</span> <span class="hljs-property">@returns</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>return <span class="hljs-subst">#{rvar}</span>;"</span> answer</pre></div></div> </li> <li id="section-135"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-135">¶</a> </div> <h3 id="op">Op</h3> </div> </li> <li id="section-136"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-136">¶</a> </div> <p>Simple Arithmetic and logical operations. Performs some conversion from CoffeeScript operations into their JavaScript equivalents.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Op = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Op</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(op, first, second, flip )</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> In first, second <span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'in'</span> <span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'do'</span> <span class="hljs-keyword">return</span> <span class="hljs-property">@generateDo</span> first <span class="hljs-keyword">if</span> op <span class="hljs-keyword">is</span> <span class="hljs-string">'new'</span> <span class="hljs-keyword">return</span> first.newInstance() <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.<span class="hljs-keyword">do</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> first.isNew first = <span class="hljs-keyword">new</span> Parens first <span class="hljs-keyword">if</span> first <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> first.bound <span class="hljs-keyword">or</span> first.<span class="hljs-keyword">do</span> <span class="hljs-property">@operator</span> = CONVERSIONS[op] <span class="hljs-keyword">or</span> op <span class="hljs-property">@first</span> = first <span class="hljs-property">@second</span> = second <span class="hljs-property">@flip</span> = !!flip <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-137"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-137">¶</a> </div> <p>The map of conversions from CoffeeScript to JavaScript symbols.</p> </div> <div class="content"><div class='highlight'><pre> CONVERSIONS = <span class="hljs-string">'=='</span>: <span class="hljs-string">'==='</span> <span class="hljs-string">'!='</span>: <span class="hljs-string">'!=='</span> <span class="hljs-string">'of'</span>: <span class="hljs-string">'in'</span> <span class="hljs-string">'yieldfrom'</span>: <span class="hljs-string">'yield*'</span></pre></div></div> </li> <li id="section-138"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-138">¶</a> </div> <p>The map of invertible operators.</p> </div> <div class="content"><div class='highlight'><pre> INVERSIONS = <span class="hljs-string">'!=='</span>: <span class="hljs-string">'==='</span> <span class="hljs-string">'==='</span>: <span class="hljs-string">'!=='</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'first'</span>, <span class="hljs-string">'second'</span>] <span class="hljs-attribute">isSimpleNumber</span>: NO <span class="hljs-attribute">isYield</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>] <span class="hljs-attribute">isYieldReturn</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@isYield</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Return <span class="hljs-attribute">isUnary</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">not</span> <span class="hljs-property">@second</span> <span class="hljs-attribute">isComplex</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">not</span> (<span class="hljs-property">@isUnary</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>] <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.isSimpleNumber())</pre></div></div> </li> <li id="section-139"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-139">¶</a> </div> <p>Am I capable of <a href="http://docs.python.org/reference/expressions.html#notin">Python-style comparison chaining</a>?</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">isChainable</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'<'</span>, <span class="hljs-string">'>'</span>, <span class="hljs-string">'>='</span>, <span class="hljs-string">'<='</span>, <span class="hljs-string">'==='</span>, <span class="hljs-string">'!=='</span>] <span class="hljs-attribute">invert</span>:<span class="hljs-function"> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isChainable</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.isChainable() allInvertable = <span class="hljs-literal">yes</span> curr = <span class="hljs-keyword">this</span> <span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator allInvertable <span class="hljs-keyword">and</span>= (curr.operator <span class="hljs-keyword">of</span> INVERSIONS) curr = curr.first <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert() <span class="hljs-keyword">unless</span> allInvertable curr = <span class="hljs-keyword">this</span> <span class="hljs-keyword">while</span> curr <span class="hljs-keyword">and</span> curr.operator curr.invert = !curr.invert curr.operator = INVERSIONS[curr.operator] curr = curr.first <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> op = INVERSIONS[<span class="hljs-property">@operator</span>] <span class="hljs-property">@operator</span> = op <span class="hljs-keyword">if</span> <span class="hljs-property">@first</span>.unwrap() <span class="hljs-keyword">instanceof</span> Op <span class="hljs-property">@first</span>.invert() <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@second</span> <span class="hljs-keyword">new</span> Parens(<span class="hljs-keyword">this</span>).invert() <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">and</span> (fst = <span class="hljs-property">@first</span>.unwrap()) <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> fst.operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'!'</span>, <span class="hljs-string">'in'</span>, <span class="hljs-string">'instanceof'</span>] fst <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'!'</span>, <span class="hljs-keyword">this</span> <span class="hljs-attribute">unfoldSoak</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@operator</span> <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> <span class="hljs-attribute">generateDo</span>: <span class="hljs-function"><span class="hljs-params">(exp)</span> -></span> passedParams = [] func = <span class="hljs-keyword">if</span> exp <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> (ref = exp.value.unwrap()) <span class="hljs-keyword">instanceof</span> Code ref <span class="hljs-keyword">else</span> exp <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> func.params <span class="hljs-keyword">or</span> [] <span class="hljs-keyword">if</span> param.value passedParams.push param.value <span class="hljs-keyword">delete</span> param.value <span class="hljs-keyword">else</span> passedParams.push param call = <span class="hljs-keyword">new</span> Call exp, passedParams call.<span class="hljs-keyword">do</span> = <span class="hljs-literal">yes</span> call <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> isChain = <span class="hljs-property">@isChainable</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.isChainable()</pre></div></div> </li> <li id="section-140"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-140">¶</a> </div> <p>In chains, there’s no need to wrap bare obj literals in parens, as the chained expression is wrapped.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-property">@first</span>.front = <span class="hljs-property">@front</span> <span class="hljs-keyword">unless</span> isChain <span class="hljs-keyword">if</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">is</span> <span class="hljs-string">'delete'</span> <span class="hljs-keyword">and</span> o.scope.check(<span class="hljs-property">@first</span>.unwrapAll().value) <span class="hljs-property">@error</span> <span class="hljs-string">'delete operand may not be argument or var'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>] <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.unwrapAll().value <span class="hljs-keyword">in</span> STRICT_PROSCRIBED <span class="hljs-property">@error</span> <span class="hljs-string">"cannot increment/decrement \"<span class="hljs-subst">#{<span class="hljs-property">@first</span>.unwrapAll().value}</span>\""</span> <span class="hljs-keyword">return</span> <span class="hljs-property">@compileYield</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@isYield</span>() <span class="hljs-keyword">return</span> <span class="hljs-property">@compileUnary</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@isUnary</span>() <span class="hljs-keyword">return</span> <span class="hljs-property">@compileChain</span> o <span class="hljs-keyword">if</span> isChain <span class="hljs-keyword">switch</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">when</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@compileExistence</span> o <span class="hljs-keyword">when</span> <span class="hljs-string">'**'</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@compilePower</span> o <span class="hljs-keyword">when</span> <span class="hljs-string">'//'</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@compileFloorDivision</span> o <span class="hljs-keyword">when</span> <span class="hljs-string">'%%'</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@compileModulo</span> o <span class="hljs-keyword">else</span> lhs = <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_OP rhs = <span class="hljs-property">@second</span>.compileToFragments o, LEVEL_OP answer = [].concat lhs, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-property">@operator</span>}</span> "</span>), rhs <span class="hljs-keyword">if</span> o.level <= LEVEL_OP <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> answer</pre></div></div> </li> <li id="section-141"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-141">¶</a> </div> <p>Mimic Python’s chained comparisons when multiple comparison operators are used sequentially. For example:</p> <pre><code>bin/coffee -e <span class="hljs-string">'console.log 50 < 65 > 10'</span> <span class="hljs-literal">true</span> </code></pre> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileChain</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [<span class="hljs-property">@first</span>.second, shared] = <span class="hljs-property">@first</span>.second.cache o fst = <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_OP fragments = fst.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@invert</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'&&'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'||'</span>}</span> "</span>), (shared.compileToFragments o), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" <span class="hljs-subst">#{<span class="hljs-property">@operator</span>}</span> "</span>), (<span class="hljs-property">@second</span>.compileToFragments o, LEVEL_OP) <span class="hljs-property">@wrapInBraces</span> fragments</pre></div></div> </li> <li id="section-142"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-142">¶</a> </div> <p>Keep reference to the left expression, unless this an existential assignment</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileExistence</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@first</span>.isComplex() ref = <span class="hljs-keyword">new</span> Literal 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, <span class="hljs-property">@first</span> <span class="hljs-keyword">else</span> fst = <span class="hljs-property">@first</span> ref = fst <span class="hljs-keyword">new</span> If(<span class="hljs-keyword">new</span> Existence(fst), ref, <span class="hljs-attribute">type</span>: <span class="hljs-string">'if'</span>).addElse(<span class="hljs-property">@second</span>).compileToFragments o</pre></div></div> </li> <li id="section-143"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-143">¶</a> </div> <p>Compile a unary <strong>Op</strong>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileUnary</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> parts = [] op = <span class="hljs-property">@operator</span> parts.push [<span class="hljs-property">@makeCode</span> 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> <span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Existence <span class="hljs-property">@first</span>.negated = <span class="hljs-keyword">not</span> <span class="hljs-property">@first</span>.negated <span class="hljs-keyword">return</span> <span class="hljs-property">@first</span>.compileToFragments o <span class="hljs-keyword">if</span> o.level >= LEVEL_ACCESS <span class="hljs-keyword">return</span> (<span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">this</span>).compileToFragments o plusMinus = op <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>] parts.push [<span class="hljs-property">@makeCode</span>(<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> <span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.operator <span class="hljs-keyword">is</span> op <span class="hljs-keyword">if</span> (plusMinus <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span> <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> <span class="hljs-property">@first</span>.isStatement o) <span class="hljs-property">@first</span> = <span class="hljs-keyword">new</span> Parens <span class="hljs-property">@first</span> parts.push <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_OP parts.reverse() <span class="hljs-keyword">if</span> <span class="hljs-property">@flip</span> <span class="hljs-property">@joinFragmentArrays</span> parts, <span class="hljs-string">''</span> <span class="hljs-attribute">compileYield</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> parts = [] op = <span class="hljs-property">@operator</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> o.scope.parent? <span class="hljs-property">@error</span> <span class="hljs-string">'yield statements must occur within a function generator.'</span> <span class="hljs-keyword">if</span> <span class="hljs-string">'expression'</span> <span class="hljs-keyword">in</span> Object.keys(<span class="hljs-property">@first</span>) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (<span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Throw) <span class="hljs-keyword">if</span> <span class="hljs-property">@isYieldReturn</span>() parts.push <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_TOP <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@first</span>.expression? parts.push <span class="hljs-property">@first</span>.expression.compileToFragments o, LEVEL_OP <span class="hljs-keyword">else</span> parts.push [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"(<span class="hljs-subst">#{op}</span> "</span>] parts.push <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_OP parts.push [<span class="hljs-property">@makeCode</span> <span class="hljs-string">")"</span>] <span class="hljs-property">@joinFragmentArrays</span> parts, <span class="hljs-string">''</span> <span class="hljs-attribute">compilePower</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span></pre></div></div> </li> <li id="section-144"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-144">¶</a> </div> <p>Make a Math.pow call</p> </div> <div class="content"><div class='highlight'><pre> pow = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'pow'</span>] <span class="hljs-keyword">new</span> Call(pow, [<span class="hljs-property">@first</span>, <span class="hljs-property">@second</span>]).compileToFragments o <span class="hljs-attribute">compileFloorDivision</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> floor = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal(<span class="hljs-string">'Math'</span>), [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'floor'</span>] div = <span class="hljs-keyword">new</span> Op <span class="hljs-string">'/'</span>, <span class="hljs-property">@first</span>, <span class="hljs-property">@second</span> <span class="hljs-keyword">new</span> Call(floor, [div]).compileToFragments o <span class="hljs-attribute">compileModulo</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> mod = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'modulo'</span>, o <span class="hljs-keyword">new</span> Call(mod, [<span class="hljs-property">@first</span>, <span class="hljs-property">@second</span>]).compileToFragments o <span class="hljs-attribute">toString</span>: <span class="hljs-function"><span class="hljs-params">(idt)</span> -></span> <span class="hljs-keyword">super</span> idt, <span class="hljs-property">@constructor</span>.name + <span class="hljs-string">' '</span> + <span class="hljs-property">@operator</span></pre></div></div> </li> <li id="section-145"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-145">¶</a> </div> <h3 id="in">In</h3> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.In = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">In</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@object</span>, <span class="hljs-property">@array</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'object'</span>, <span class="hljs-string">'array'</span>] <span class="hljs-attribute">invert</span>: NEGATE <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@array</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-property">@array</span>.isArray() <span class="hljs-keyword">and</span> <span class="hljs-property">@array</span>.base.objects.length <span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> <span class="hljs-property">@array</span>.base.objects <span class="hljs-keyword">when</span> obj <span class="hljs-keyword">instanceof</span> Splat hasSplat = <span class="hljs-literal">yes</span> <span class="hljs-keyword">break</span></pre></div></div> </li> <li id="section-146"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-146">¶</a> </div> <p><code>compileOrTest</code> only if we have an array literal with no splats</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-property">@compileOrTest</span> o <span class="hljs-keyword">unless</span> hasSplat <span class="hljs-property">@compileLoopTest</span> o <span class="hljs-attribute">compileOrTest</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [sub, ref] = <span class="hljs-property">@object</span>.cache o, LEVEL_OP [cmp, cnj] = <span class="hljs-keyword">if</span> <span class="hljs-property">@negated</span> <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">' || '</span>] tests = [] <span class="hljs-keyword">for</span> item, i <span class="hljs-keyword">in</span> <span class="hljs-property">@array</span>.base.objects <span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> tests.push <span class="hljs-property">@makeCode</span> 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), <span class="hljs-property">@makeCode</span>(cmp), item.compileToFragments(o, LEVEL_ACCESS) <span class="hljs-keyword">if</span> o.level < LEVEL_OP <span class="hljs-keyword">then</span> tests <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> tests <span class="hljs-attribute">compileLoopTest</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [sub, ref] = <span class="hljs-property">@object</span>.cache o, LEVEL_LIST fragments = [].concat <span class="hljs-property">@makeCode</span>(utility(<span class="hljs-string">'indexOf'</span>, o) + <span class="hljs-string">".call("</span>), <span class="hljs-property">@array</span>.compileToFragments(o, LEVEL_LIST), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">", "</span>), ref, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") "</span> + <span class="hljs-keyword">if</span> <span class="hljs-property">@negated</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'< 0'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'>= 0'</span>) <span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> fragmentsToText(sub) <span class="hljs-keyword">is</span> fragmentsToText(ref) fragments = sub.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">', '</span>), fragments <span class="hljs-keyword">if</span> o.level < LEVEL_LIST <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> fragments <span class="hljs-attribute">toString</span>: <span class="hljs-function"><span class="hljs-params">(idt)</span> -></span> <span class="hljs-keyword">super</span> idt, <span class="hljs-property">@constructor</span>.name + <span class="hljs-keyword">if</span> <span class="hljs-property">@negated</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span></pre></div></div> </li> <li id="section-147"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-147">¶</a> </div> <h3 id="try">Try</h3> </div> </li> <li id="section-148"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-148">¶</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Try = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Try</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@attempt</span>, <span class="hljs-property">@errorVariable</span>, <span class="hljs-property">@recovery</span>, <span class="hljs-property">@ensure</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'attempt'</span>, <span class="hljs-string">'recovery'</span>, <span class="hljs-string">'ensure'</span>] <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">jumps</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@attempt</span>.jumps(o) <span class="hljs-keyword">or</span> <span class="hljs-property">@recovery</span>?.jumps(o) <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> <span class="hljs-property">@attempt</span> = <span class="hljs-property">@attempt</span> .makeReturn res <span class="hljs-keyword">if</span> <span class="hljs-property">@attempt</span> <span class="hljs-property">@recovery</span> = <span class="hljs-property">@recovery</span>.makeReturn res <span class="hljs-keyword">if</span> <span class="hljs-property">@recovery</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-149"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-149">¶</a> </div> <p>Compilation is more or less as you would expect — the <em>finally</em> clause is optional, the <em>catch</em> is not.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o.indent += TAB tryPart = <span class="hljs-property">@attempt</span>.compileToFragments o, LEVEL_TOP catchPart = <span class="hljs-keyword">if</span> <span class="hljs-property">@recovery</span> generatedErrorVariableName = o.scope.freeVariable <span class="hljs-string">'error'</span> placeholder = <span class="hljs-keyword">new</span> Literal generatedErrorVariableName <span class="hljs-property">@recovery</span>.unshift <span class="hljs-keyword">new</span> Assign <span class="hljs-property">@errorVariable</span>, placeholder <span class="hljs-keyword">if</span> <span class="hljs-property">@errorVariable</span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" catch ("</span>), placeholder.compileToFragments(o), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") {\n"</span>), <span class="hljs-property">@recovery</span>.compileToFragments(o, LEVEL_TOP), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span>) <span class="hljs-keyword">else</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@ensure</span> <span class="hljs-keyword">or</span> <span class="hljs-property">@recovery</span> [<span class="hljs-property">@makeCode</span>(<span class="hljs-string">" catch (<span class="hljs-subst">#{generatedErrorVariableName}</span>) {}"</span>)] <span class="hljs-keyword">else</span> [] ensurePart = <span class="hljs-keyword">if</span> <span class="hljs-property">@ensure</span> <span class="hljs-keyword">then</span> ([].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" finally {\n"</span>), <span class="hljs-property">@ensure</span>.compileToFragments(o, LEVEL_TOP), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span>)) <span class="hljs-keyword">else</span> [] [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>try {\n"</span>), tryPart, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span>), catchPart, ensurePart</pre></div></div> </li> <li id="section-150"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-150">¶</a> </div> <h3 id="throw">Throw</h3> </div> </li> <li id="section-151"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-151">¶</a> </div> <p>Simple node to throw an exception.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Throw = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Throw</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@expression</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'expression'</span>] <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">jumps</span>: NO</pre></div></div> </li> <li id="section-152"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-152">¶</a> </div> <p>A <strong>Throw</strong> is already a return, of sorts…</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">makeReturn</span>: THIS <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-property">@tab</span> + <span class="hljs-string">"throw "</span>), <span class="hljs-property">@expression</span>.compileToFragments(o), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">";"</span>)</pre></div></div> </li> <li id="section-153"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-153">¶</a> </div> <h3 id="existence">Existence</h3> </div> </li> <li id="section-154"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-154">¶</a> </div> <p>Checks a variable for existence — not <em>null</em> and not <em>undefined</em>. This is similar to <code>.nil?</code> in Ruby, and avoids having to consult a JavaScript truth table.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Existence = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Existence</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@expression</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'expression'</span>] <span class="hljs-attribute">invert</span>: NEGATE <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@expression</span>.front = <span class="hljs-property">@front</span> code = <span class="hljs-property">@expression</span>.compile o, LEVEL_OP <span class="hljs-keyword">if</span> IDENTIFIER.test(code) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> o.scope.check code [cmp, cnj] = <span class="hljs-keyword">if</span> <span class="hljs-property">@negated</span> <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">'&&'</span>] 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> <li id="section-155"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-155">¶</a> </div> <p>do not use strict equality here; it will break existing code</p> </div> <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> <span class="hljs-property">@negated</span> <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> [<span class="hljs-property">@makeCode</span>(<span class="hljs-keyword">if</span> o.level <= LEVEL_COND <span class="hljs-keyword">then</span> code <span class="hljs-keyword">else</span> <span class="hljs-string">"(<span class="hljs-subst">#{code}</span>)"</span>)]</pre></div></div> </li> <li id="section-156"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-156">¶</a> </div> <h3 id="parens">Parens</h3> </div> </li> <li id="section-157"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-157">¶</a> </div> <p>An extra set of parentheses, specified explicitly in the source. At one time we tried to clean up the results by detecting and removing redundant parentheses, but no longer — you can put in as many as you please.</p> <p>Parentheses are a good way to force any statement to become an expression.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Parens = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parens</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@body</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'body'</span>] unwrap :<span class="hljs-function"> -></span> <span class="hljs-property">@body</span> isComplex :<span class="hljs-function"> -></span> <span class="hljs-property">@body</span>.isComplex() <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> expr = <span class="hljs-property">@body</span>.unwrap() <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> expr.isAtomic() expr.front = <span class="hljs-property">@front</span> <span class="hljs-keyword">return</span> expr.compileToFragments o fragments = expr.compileToFragments o, LEVEL_PAREN bare = o.level < LEVEL_OP <span class="hljs-keyword">and</span> (expr <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">or</span> expr <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">or</span> (expr <span class="hljs-keyword">instanceof</span> For <span class="hljs-keyword">and</span> expr.returns)) <span class="hljs-keyword">if</span> bare <span class="hljs-keyword">then</span> fragments <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> fragments</pre></div></div> </li> <li id="section-158"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-158">¶</a> </div> <h3 id="for">For</h3> </div> </li> <li id="section-159"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-159">¶</a> </div> <p>CoffeeScript’s replacement for the <em>for</em> loop is our array and object comprehensions, that compile into <em>for</em> loops here. They also act as an expression, able to return the result of each filtered iteration.</p> <p>Unlike Python array comprehensions, they can be multi-line, and you can pass the current index of the loop as a second parameter. Unlike Ruby blocks, you can map and filter in a single pass.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.For = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">For</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">While</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(body, source)</span> -></span> {<span class="hljs-property">@source</span>, <span class="hljs-property">@guard</span>, <span class="hljs-property">@step</span>, <span class="hljs-property">@name</span>, <span class="hljs-property">@index</span>} = source <span class="hljs-property">@body</span> = Block.wrap [body] <span class="hljs-property">@own</span> = !!source.own <span class="hljs-property">@object</span> = !!source.object [<span class="hljs-property">@name</span>, <span class="hljs-property">@index</span>] = [<span class="hljs-property">@index</span>, <span class="hljs-property">@name</span>] <span class="hljs-keyword">if</span> <span class="hljs-property">@object</span> <span class="hljs-property">@index</span>.error <span class="hljs-string">'index cannot be a pattern matching expression'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@index</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-property">@range</span> = <span class="hljs-property">@source</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-property">@source</span>.base <span class="hljs-keyword">instanceof</span> Range <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@source</span>.properties.length <span class="hljs-property">@pattern</span> = <span class="hljs-property">@name</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-property">@index</span>.error <span class="hljs-string">'indexes do not apply to range loops'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@range</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@index</span> <span class="hljs-property">@name</span>.error <span class="hljs-string">'cannot pattern match over range loops'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@range</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@pattern</span> <span class="hljs-property">@name</span>.error <span class="hljs-string">'cannot use own with for-in'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@own</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@object</span> <span class="hljs-property">@returns</span> = <span class="hljs-literal">false</span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'body'</span>, <span class="hljs-string">'source'</span>, <span class="hljs-string">'guard'</span>, <span class="hljs-string">'step'</span>]</pre></div></div> </li> <li id="section-160"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-160">¶</a> </div> <p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner loop, filtering, stepping, and result saving for array, object, and range comprehensions. Some of the generated code can be shared in common, and some cannot.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> body = Block.wrap [<span class="hljs-property">@body</span>] [..., last] = body.expressions <span class="hljs-property">@returns</span> = <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> <span class="hljs-property">@range</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@source</span>.base <span class="hljs-keyword">else</span> <span class="hljs-property">@source</span> scope = o.scope name = <span class="hljs-property">@name</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@name</span>.compile o, LEVEL_LIST) <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@pattern</span> index = <span class="hljs-property">@index</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@index</span>.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> <span class="hljs-property">@pattern</span> scope.find(index) <span class="hljs-keyword">if</span> index rvar = scope.freeVariable <span class="hljs-string">'results'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@returns</span> ivar = (<span class="hljs-property">@object</span> <span class="hljs-keyword">and</span> index) <span class="hljs-keyword">or</span> scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span> kvar = (<span class="hljs-property">@range</span> <span class="hljs-keyword">and</span> name) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">or</span> ivar kvarAssign = <span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> = "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@step</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@range</span> [step, stepVar] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@step</span>.cache o, LEVEL_LIST, isComplexOrAssignable stepNum = stepVar.match NUMBER name = ivar <span class="hljs-keyword">if</span> <span class="hljs-property">@pattern</span> varPart = <span class="hljs-string">''</span> guardPart = <span class="hljs-string">''</span> defPart = <span class="hljs-string">''</span> idt1 = <span class="hljs-property">@tab</span> + TAB <span class="hljs-keyword">if</span> <span class="hljs-property">@range</span> forPartFragments = source.compileToFragments merge o, {<span class="hljs-attribute">index</span>: ivar, name, <span class="hljs-property">@step</span>, <span class="hljs-attribute">isComplex</span>: isComplexOrAssignable} <span class="hljs-keyword">else</span> svar = <span class="hljs-property">@source</span>.compile o, LEVEL_LIST <span class="hljs-keyword">if</span> (name <span class="hljs-keyword">or</span> <span class="hljs-property">@own</span>) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> IDENTIFIER.test svar defPart += <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{ref = scope.freeVariable <span class="hljs-string">'ref'</span>}</span> = <span class="hljs-subst">#{svar}</span>;\n"</span> svar = ref <span class="hljs-keyword">if</span> name <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@pattern</span> namePart = <span class="hljs-string">"<span class="hljs-subst">#{name}</span> = <span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@object</span> defPart += <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{step}</span>;\n"</span> <span class="hljs-keyword">if</span> step <span class="hljs-keyword">isnt</span> stepVar lvar = scope.freeVariable <span class="hljs-string">'len'</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@step</span> <span class="hljs-keyword">and</span> stepNum <span class="hljs-keyword">and</span> down = (parseNum(stepNum[<span class="hljs-number">0</span>]) < <span class="hljs-number">0</span>) 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> < <span class="hljs-subst">#{lvar}</span>"</span> compareDown = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> >= 0"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@step</span> <span class="hljs-keyword">if</span> stepNum <span class="hljs-keyword">if</span> down compare = compareDown declare = declareDown <span class="hljs-keyword">else</span> compare = <span class="hljs-string">"<span class="hljs-subst">#{stepVar}</span> > 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> > 0 ? (<span class="hljs-subst">#{declare}</span>) : <span class="hljs-subst">#{declareDown}</span>)"</span> increment = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> += <span class="hljs-subst">#{stepVar}</span>"</span> <span class="hljs-keyword">else</span> increment = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"++<span class="hljs-subst">#{ivar}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>}</span>"</span> forPartFragments = [<span class="hljs-property">@makeCode</span>(<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> <span class="hljs-property">@returns</span> resultPart = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{rvar}</span> = [];\n"</span> returnResult = <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>return <span class="hljs-subst">#{rvar}</span>;"</span> body.makeReturn rvar <span class="hljs-keyword">if</span> <span class="hljs-property">@guard</span> <span class="hljs-keyword">if</span> body.expressions.length > <span class="hljs-number">1</span> body.expressions.unshift <span class="hljs-keyword">new</span> If (<span class="hljs-keyword">new</span> Parens <span class="hljs-property">@guard</span>).invert(), <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"continue"</span> <span class="hljs-keyword">else</span> body = Block.wrap [<span class="hljs-keyword">new</span> If <span class="hljs-property">@guard</span>, body] <span class="hljs-keyword">if</span> <span class="hljs-property">@guard</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@pattern</span> body.expressions.unshift <span class="hljs-keyword">new</span> Assign <span class="hljs-property">@name</span>, <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{svar}</span>[<span class="hljs-subst">#{kvar}</span>]"</span> defPartFragments = [].concat <span class="hljs-property">@makeCode</span>(defPart), <span class="hljs-property">@pluckDirectCall</span>(o, body) varPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span><span class="hljs-subst">#{namePart}</span>;"</span> <span class="hljs-keyword">if</span> namePart <span class="hljs-keyword">if</span> <span class="hljs-property">@object</span> forPartFragments = [<span class="hljs-property">@makeCode</span>(<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> <span class="hljs-property">@own</span> bodyFragments = body.compileToFragments merge(o, <span class="hljs-attribute">indent</span>: idt1), LEVEL_TOP <span class="hljs-keyword">if</span> bodyFragments <span class="hljs-keyword">and</span> (bodyFragments.length > <span class="hljs-number">0</span>) bodyFragments = [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), bodyFragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>) [].concat defPartFragments, <span class="hljs-property">@makeCode</span>(<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">#{<span class="hljs-property">@tab</span>}</span>for ("</span>), forPartFragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") {<span class="hljs-subst">#{guardPart}</span><span class="hljs-subst">#{varPart}</span>"</span>), bodyFragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}<span class="hljs-subst">#{returnResult <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span>"</span>) <span class="hljs-attribute">pluckDirectCall</span>: <span class="hljs-function"><span class="hljs-params">(o, body)</span> -></span> defs = [] <span class="hljs-keyword">for</span> expr, idx <span class="hljs-keyword">in</span> body.expressions expr = expr.unwrapAll() <span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> expr <span class="hljs-keyword">instanceof</span> Call val = expr.variable?.unwrapAll() <span class="hljs-keyword">continue</span> <span class="hljs-keyword">unless</span> (val <span class="hljs-keyword">instanceof</span> Code) <span class="hljs-keyword">or</span> (val <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> val.base?.unwrapAll() <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> val.properties.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> val.properties[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">in</span> [<span class="hljs-string">'call'</span>, <span class="hljs-string">'apply'</span>]) fn = val.base?.unwrapAll() <span class="hljs-keyword">or</span> val ref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'fn'</span> base = <span class="hljs-keyword">new</span> Value ref <span class="hljs-keyword">if</span> val.base [val.base, base] = [base, val] body.expressions[idx] = <span class="hljs-keyword">new</span> Call base, expr.args defs = defs.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-property">@tab</span>), (<span class="hljs-keyword">new</span> Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">';\n'</span>) defs</pre></div></div> </li> <li id="section-161"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-161">¶</a> </div> <h3 id="switch">Switch</h3> </div> </li> <li id="section-162"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-162">¶</a> </div> <p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Switch = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Switch</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@subject</span>, <span class="hljs-property">@cases</span>, <span class="hljs-property">@otherwise</span>)</span> -></span> <span class="hljs-attribute">children</span>: [<span class="hljs-string">'subject'</span>, <span class="hljs-string">'cases'</span>, <span class="hljs-string">'otherwise'</span>] <span class="hljs-attribute">isStatement</span>: YES <span class="hljs-attribute">jumps</span>: <span class="hljs-function"><span class="hljs-params">(o = {block: <span class="hljs-literal">yes</span>})</span> -></span> <span class="hljs-keyword">for</span> [conds, block] <span class="hljs-keyword">in</span> <span class="hljs-property">@cases</span> <span class="hljs-keyword">return</span> jumpNode <span class="hljs-keyword">if</span> jumpNode = block.jumps o <span class="hljs-property">@otherwise</span>?.jumps o <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> pair[<span class="hljs-number">1</span>].makeReturn res <span class="hljs-keyword">for</span> pair <span class="hljs-keyword">in</span> <span class="hljs-property">@cases</span> <span class="hljs-property">@otherwise</span> <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 <span class="hljs-property">@otherwise</span>?.makeReturn res <span class="hljs-keyword">this</span> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> idt1 = o.indent + TAB idt2 = o.indent = idt1 + TAB fragments = [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-property">@tab</span> + <span class="hljs-string">"switch ("</span>), (<span class="hljs-keyword">if</span> <span class="hljs-property">@subject</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@subject</span>.compileToFragments(o, LEVEL_PAREN) <span class="hljs-keyword">else</span> <span class="hljs-property">@makeCode</span> <span class="hljs-string">"false"</span>), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") {\n"</span>) <span class="hljs-keyword">for</span> [conditions, block], i <span class="hljs-keyword">in</span> <span class="hljs-property">@cases</span> <span class="hljs-keyword">for</span> cond <span class="hljs-keyword">in</span> flatten [conditions] cond = cond.invert() <span class="hljs-keyword">unless</span> <span class="hljs-property">@subject</span> fragments = fragments.concat <span class="hljs-property">@makeCode</span>(idt1 + <span class="hljs-string">"case "</span>), cond.compileToFragments(o, LEVEL_PAREN), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">":\n"</span>) fragments = fragments.concat body, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-keyword">if</span> (body = block.compileToFragments o, LEVEL_TOP).length > <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> <span class="hljs-property">@cases</span>.length - <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@otherwise</span> expr = <span class="hljs-property">@lastNonComment</span> block.expressions <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> expr <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">or</span> (expr <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> expr.jumps() <span class="hljs-keyword">and</span> expr.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'debugger'</span>) fragments.push cond.makeCode(idt2 + <span class="hljs-string">'break;\n'</span>) <span class="hljs-keyword">if</span> <span class="hljs-property">@otherwise</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@otherwise</span>.expressions.length fragments.push <span class="hljs-property">@makeCode</span>(idt1 + <span class="hljs-string">"default:\n"</span>), (<span class="hljs-property">@otherwise</span>.compileToFragments o, LEVEL_TOP)..., <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>) fragments.push <span class="hljs-property">@makeCode</span> <span class="hljs-property">@tab</span> + <span class="hljs-string">'}'</span> fragments</pre></div></div> </li> <li id="section-163"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-163">¶</a> </div> <h3 id="if">If</h3> </div> </li> <li id="section-164"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-164">¶</a> </div> <p><em>If/else</em> statements. Acts as an expression by pushing down requested returns to the last line of each clause.</p> <p>Single-expression <strong>Ifs</strong> are compiled into conditional operators if possible, because ternaries are already proper expressions, and don’t need conversion.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.If = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">If</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(condition, <span class="hljs-property">@body</span>, options = {})</span> -></span> <span class="hljs-property">@condition</span> = <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 <span class="hljs-property">@elseBody</span> = <span class="hljs-literal">null</span> <span class="hljs-property">@isChain</span> = <span class="hljs-literal">false</span> {<span class="hljs-property">@soak</span>} = options <span class="hljs-attribute">children</span>: [<span class="hljs-string">'condition'</span>, <span class="hljs-string">'body'</span>, <span class="hljs-string">'elseBody'</span>] <span class="hljs-attribute">bodyNode</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@body</span>?.unwrap() <span class="hljs-attribute">elseBodyNode</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@elseBody</span>?.unwrap()</pre></div></div> </li> <li id="section-165"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-165">¶</a> </div> <p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">addElse</span>: <span class="hljs-function"><span class="hljs-params">(elseBody)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isChain</span> <span class="hljs-property">@elseBodyNode</span>().addElse elseBody <span class="hljs-keyword">else</span> <span class="hljs-property">@isChain</span> = elseBody <span class="hljs-keyword">instanceof</span> If <span class="hljs-property">@elseBody</span> = <span class="hljs-property">@ensureBlock</span> elseBody <span class="hljs-property">@elseBody</span>.updateLocationDataIfMissing elseBody.locationData <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-166"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-166">¶</a> </div> <p>The <strong>If</strong> only compiles into a statement if either of its bodies needs to be a statement. Otherwise a conditional operator is safe.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">isStatement</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> o?.level <span class="hljs-keyword">is</span> LEVEL_TOP <span class="hljs-keyword">or</span> <span class="hljs-property">@bodyNode</span>().isStatement(o) <span class="hljs-keyword">or</span> <span class="hljs-property">@elseBodyNode</span>()?.isStatement(o) <span class="hljs-attribute">jumps</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-property">@body</span>.jumps(o) <span class="hljs-keyword">or</span> <span class="hljs-property">@elseBody</span>?.jumps(o) <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isStatement</span> o <span class="hljs-keyword">then</span> <span class="hljs-property">@compileStatement</span> o <span class="hljs-keyword">else</span> <span class="hljs-property">@compileExpression</span> o <span class="hljs-attribute">makeReturn</span>: <span class="hljs-function"><span class="hljs-params">(res)</span> -></span> <span class="hljs-property">@elseBody</span> <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 <span class="hljs-property">@body</span> <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-property">@body</span>.makeReturn res] <span class="hljs-property">@elseBody</span> <span class="hljs-keyword">and</span>= <span class="hljs-keyword">new</span> Block [<span class="hljs-property">@elseBody</span>.makeReturn res] <span class="hljs-keyword">this</span> <span class="hljs-attribute">ensureBlock</span>: <span class="hljs-function"><span class="hljs-params">(node)</span> -></span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Block <span class="hljs-keyword">then</span> node <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Block [node]</pre></div></div> </li> <li id="section-167"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-167">¶</a> </div> <p>Compile the <code>If</code> as a regular <em>if-else</em> statement. Flattened chains force inner <em>else</em> bodies into statement form.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileStatement</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> child = del o, <span class="hljs-string">'chainChild'</span> exeq = del o, <span class="hljs-string">'isExistentialEquals'</span> <span class="hljs-keyword">if</span> exeq <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> If(<span class="hljs-property">@condition</span>.invert(), <span class="hljs-property">@elseBodyNode</span>(), <span class="hljs-attribute">type</span>: <span class="hljs-string">'if'</span>).compileToFragments o indent = o.indent + TAB cond = <span class="hljs-property">@condition</span>.compileToFragments o, LEVEL_PAREN body = <span class="hljs-property">@ensureBlock</span>(<span class="hljs-property">@body</span>).compileToFragments merge o, {indent} ifPart = [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"if ("</span>), cond, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") {\n"</span>), body, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span>) ifPart.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-property">@tab</span> <span class="hljs-keyword">unless</span> child <span class="hljs-keyword">return</span> ifPart <span class="hljs-keyword">unless</span> <span class="hljs-property">@elseBody</span> answer = ifPart.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">' else '</span>) <span class="hljs-keyword">if</span> <span class="hljs-property">@isChain</span> o.chainChild = <span class="hljs-literal">yes</span> answer = answer.concat <span class="hljs-property">@elseBody</span>.unwrap().compileToFragments o, LEVEL_TOP <span class="hljs-keyword">else</span> answer = answer.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"{\n"</span>), <span class="hljs-property">@elseBody</span>.compileToFragments(merge(o, {indent}), LEVEL_TOP), <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span>) answer</pre></div></div> </li> <li id="section-168"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-168">¶</a> </div> <p>Compile the <code>If</code> as a conditional operator.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileExpression</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> cond = <span class="hljs-property">@condition</span>.compileToFragments o, LEVEL_COND body = <span class="hljs-property">@bodyNode</span>().compileToFragments o, LEVEL_LIST alt = <span class="hljs-keyword">if</span> <span class="hljs-property">@elseBodyNode</span>() <span class="hljs-keyword">then</span> <span class="hljs-property">@elseBodyNode</span>().compileToFragments(o, LEVEL_LIST) <span class="hljs-keyword">else</span> [<span class="hljs-property">@makeCode</span>(<span class="hljs-string">'void 0'</span>)] fragments = cond.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" ? "</span>), body, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" : "</span>), alt <span class="hljs-keyword">if</span> o.level >= LEVEL_COND <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> fragments <span class="hljs-keyword">else</span> fragments <span class="hljs-attribute">unfoldSoak</span>:<span class="hljs-function"> -></span> <span class="hljs-property">@soak</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">this</span></pre></div></div> </li> <li id="section-169"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-169">¶</a> </div> <h2 id="constants">Constants</h2> </div> </li> <li id="section-170"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-170">¶</a> </div> </div> <div class="content"><div class='highlight'><pre> UTILITIES =</pre></div></div> </li> <li id="section-171"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-171">¶</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference to the superclass for <code>super()</code> calls, and copies of any static properties.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">extend</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -></span> <span class="hljs-string">" function(child, parent) { for (var key in parent) { if (<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; } "</span></pre></div></div> </li> <li id="section-172"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-172">¶</a> </div> <p>Create a function bound to the current value of “this”.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">bind</span>:<span class="hljs-function"> -></span> <span class="hljs-string">' function(fn, me){ return function(){ return fn.apply(me, arguments); }; } '</span></pre></div></div> </li> <li id="section-173"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-173">¶</a> </div> <p>Discover if an item is in an array.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">indexOf</span>:<span class="hljs-function"> -></span> <span class="hljs-string">" [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; } "</span> <span class="hljs-attribute">modulo</span>:<span class="hljs-function"> -></span> <span class="hljs-string">""" function(a, b) { return (+a % (b = +b) + b) % b; } """</span></pre></div></div> </li> <li id="section-174"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-174">¶</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">hasProp</span>:<span class="hljs-function"> -></span> <span class="hljs-string">'{}.hasOwnProperty'</span> slice :<span class="hljs-function"> -></span> <span class="hljs-string">'[].slice'</span></pre></div></div> </li> <li id="section-175"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-175">¶</a> </div> <p>Levels indicate a node’s position in the AST. Useful for knowing if parens are necessary or superfluous.</p> </div> <div class="content"><div class='highlight'><pre>LEVEL_TOP = <span class="hljs-number">1</span> <span class="hljs-comment"># ...;</span> LEVEL_PAREN = <span class="hljs-number">2</span> <span class="hljs-comment"># (...)</span> LEVEL_LIST = <span class="hljs-number">3</span> <span class="hljs-comment"># [...]</span> LEVEL_COND = <span class="hljs-number">4</span> <span class="hljs-comment"># ... ? x : y</span> LEVEL_OP = <span class="hljs-number">5</span> <span class="hljs-comment"># !...</span> LEVEL_ACCESS = <span class="hljs-number">6</span> <span class="hljs-comment"># ...[0]</span></pre></div></div> </li> <li id="section-176"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-176">¶</a> </div> <p>Tabs are two spaces for pretty printing.</p> </div> <div class="content"><div class='highlight'><pre>TAB = <span class="hljs-string">' '</span> IDENTIFIER = <span class="hljs-regexp">/// ^ (?!\d) [$\w\x7f-\uffff]+ $ ///</span> SIMPLENUM = <span class="hljs-regexp">/^[+-]?\d+$/</span> HEXNUM = <span class="hljs-regexp">/^[+-]?0x[\da-f]+/i</span> NUMBER = <span class="hljs-regexp">///^[+-]?(?: 0x[\da-f]+ | <span class="hljs-comment"># hex</span> \d*\.?\d+ (?:e[+-]?\d+)? <span class="hljs-comment"># decimal</span> )$///</span>i</pre></div></div> </li> <li id="section-177"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-177">¶</a> </div> <p>Is a literal value a string/regex?</p> </div> <div class="content"><div class='highlight'><pre>IS_STRING = <span class="hljs-regexp">/^['"]/</span> IS_REGEX = <span class="hljs-regexp">/^\//</span></pre></div></div> </li> <li id="section-178"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-178">¶</a> </div> <h2 id="helper-functions">Helper Functions</h2> </div> </li> <li id="section-179"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-179">¶</a> </div> </div> </li> <li id="section-180"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-180">¶</a> </div> <p>Helper for ensuring that utility functions are assigned at the top level.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">utility</span> = <span class="hljs-params">(name, o)</span> -></span> {root} = o.scope <span class="hljs-keyword">if</span> name <span class="hljs-keyword">of</span> root.utilities root.utilities[name] <span class="hljs-keyword">else</span> ref = root.freeVariable name root.assign ref, UTILITIES[name] o root.utilities[name] = ref <span class="hljs-function"><span class="hljs-title">multident</span> = <span class="hljs-params">(code, tab)</span> -></span> code = code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'$&'</span> + tab code.replace <span class="hljs-regexp">/\s+$/</span>, <span class="hljs-string">''</span></pre></div></div> </li> <li id="section-181"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-181">¶</a> </div> <p>Parse a number (+- decimal/hexadecimal) Examples: 0, -1, 1, 2e3, 2e-3, -0xfe, 0xfe</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">parseNum</span> = <span class="hljs-params">(x)</span> -></span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> x? <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> x.match HEXNUM parseInt x, <span class="hljs-number">16</span> <span class="hljs-keyword">else</span> parseFloat x <span class="hljs-function"><span class="hljs-title">isLiteralArguments</span> = <span class="hljs-params">(node)</span> -></span> 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 <span class="hljs-function"><span class="hljs-title">isLiteralThis</span> = <span class="hljs-params">(node)</span> -></span> (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">'this'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> node.asKey) <span class="hljs-keyword">or</span> (node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound) <span class="hljs-keyword">or</span> (node <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> node.isSuper) <span class="hljs-function"><span class="hljs-title">isComplexOrAssignable</span> = <span class="hljs-params">(node)</span> -></span> node.isComplex() <span class="hljs-keyword">or</span> node.isAssignable?()</pre></div></div> </li> <li id="section-182"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-182">¶</a> </div> <p>Unfold a node’s child if soak, then tuck the node under created <code>If</code></p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">unfoldSoak</span> = <span class="hljs-params">(o, parent, name)</span> -></span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> ifn = parent[name].unfoldSoak o parent[name] = ifn.body ifn.body = <span class="hljs-keyword">new</span> Value parent ifn</pre></div></div> </li> </ul> </div> </body> </html>