UNPKG

coffeescript

Version:

Unfancy JavaScript

250 lines (237 loc) 111 kB
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_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="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt matches against the beginning of the source code. When a match is found, a token is produced, we consume the match, and start again. Tokens are in the form:</p> <pre><code>[tag, value, lineNumber] </code></pre> <p>Which is a format that can be fed directly into <a href="http://github.com/zaach/jison">Jison</a>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">Rewriter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;./rewriter&#39;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">count</span><span class="p">,</span> <span class="nx">starts</span><span class="p">,</span> <span class="nx">compact</span><span class="p">,</span> <span class="nx">last</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;./helpers&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvies it up into tagged tokens. Some potential ambiguity in the grammar has been avoided by pushing some extra smarts into the Lexer.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Lexer = </span><span class="nx">class</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p><strong>tokenize</strong> is the Lexer's main method. Scan by attempting to match tokens one at a time, using a regular expression anchored at the start of the remaining code, or a custom recursive token-matching method (for interpolations). When the next token has been recorded, we move forward within the code past the token, and begin again.</p> <p>Each tokenizing method is responsible for returning the number of characters it has consumed.</p> <p>Before returning the token stream, run it through the <a href="rewriter.html">Rewriter</a> unless explicitly asked not to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tokenize</span><span class="o">:</span> <span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">opts = </span><span class="p">{})</span> <span class="o">-&gt;</span> <span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\r/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">replace</span> <span class="nx">TRAILING_SPACES</span><span class="p">,</span> <span class="s1">&#39;&#39;</span> <span class="vi">@code = </span><span class="nx">code</span> <span class="c1"># The remainder of the source code.</span> <span class="vi">@line = </span><span class="nx">opts</span><span class="p">.</span><span class="nx">line</span> <span class="o">or</span> <span class="mi">0</span> <span class="c1"># The current line.</span> <span class="vi">@indent = </span><span class="mi">0</span> <span class="c1"># The current indentation level.</span> <span class="vi">@indebt = </span><span class="mi">0</span> <span class="c1"># The over-indentation at the current level.</span> <span class="vi">@outdebt = </span><span class="mi">0</span> <span class="c1"># The under-outdentation at the current level.</span> <span class="vi">@indents = </span><span class="p">[]</span> <span class="c1"># The stack of all current indentation levels.</span> <span class="vi">@tokens = </span><span class="p">[]</span> <span class="c1"># Stream of parsed tokens in the form `[&#39;TYPE&#39;, value, line]`.</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>At every position, run through this list of attempted matches, short-circuiting if any of them succeed. Their order determines precedence: <code>@literalToken</code> is the fallback catch-all.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">i = </span><span class="mi">0</span> <span class="k">while</span> <span class="vi">@chunk = </span><span class="nx">code</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span> <span class="nx">i</span> <span class="o">+=</span> <span class="nx">@identifierToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@commentToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@whitespaceToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@lineToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@heredocToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@stringToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@numberToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@regexToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@jsToken</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@literalToken</span><span class="p">()</span> <span class="nx">@closeIndentation</span><span class="p">()</span> <span class="k">return</span> <span class="nx">@tokens</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">rewrite</span> <span class="o">is</span> <span class="kc">off</span> <span class="p">(</span><span class="k">new</span> <span class="nx">Rewriter</span><span class="p">).</span><span class="nx">rewrite</span> <span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <h2>Tokenizers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>Matches identifying literals: variables, keywords, method names, etc. Check to ensure that JavaScript reserved words aren't being used as identifiers. Because CoffeeScript reserves a handful of keywords that are allowed in JavaScript, we're careful not to tag them as keywords when referenced as property names here, so you can still do <code>jQuery.is()</code> even though <code>is</code> means <code>===</code> otherwise.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">identifierToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="p">[</span><span class="nx">input</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">colon</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span> <span class="k">if</span> <span class="nx">id</span> <span class="o">is</span> <span class="s1">&#39;all&#39;</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;FOR&#39;</span> <span class="nx">@token</span> <span class="s1">&#39;ALL&#39;</span><span class="p">,</span> <span class="nx">id</span> <span class="k">return</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span> <span class="nv">forcedIdentifier = </span><span class="nx">colon</span> <span class="o">or</span> <span class="p">(</span><span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="s1">&#39;?.&#39;</span><span class="p">,</span> <span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;::&#39;</span><span class="p">]</span> <span class="nv">tag = </span><span class="s1">&#39;IDENTIFIER&#39;</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">JS_KEYWORDS</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">forcedIdentifier</span> <span class="o">and</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_KEYWORDS</span> <span class="nv">tag = </span><span class="nx">id</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;WHEN&#39;</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">()</span> <span class="k">in</span> <span class="nx">LINE_BREAK</span> <span class="nv">tag = </span><span class="s1">&#39;LEADING_WHEN&#39;</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;FOR&#39;</span> <span class="vi">@seenFor = </span><span class="kc">yes</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">UNARY</span> <span class="nv">tag = </span><span class="s1">&#39;UNARY&#39;</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">RELATION</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">&#39;INSTANCEOF&#39;</span> <span class="o">and</span> <span class="nx">@seenFor</span> <span class="vi">@seenFor = </span><span class="kc">no</span> <span class="nv">tag = </span><span class="s1">&#39;FOR&#39;</span> <span class="o">+</span> <span class="nx">tag</span> <span class="k">else</span> <span class="nv">tag = </span><span class="s1">&#39;RELATION&#39;</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;!&#39;</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="nv">id = </span><span class="s1">&#39;!&#39;</span> <span class="o">+</span> <span class="nx">id</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">JS_FORBIDDEN</span> <span class="k">if</span> <span class="nx">forcedIdentifier</span> <span class="nv">tag = </span><span class="s1">&#39;IDENTIFIER&#39;</span> <span class="nv">id = </span><span class="k">new</span> <span class="nb">String</span> <span class="nx">id</span> <span class="nv">id.reserved = </span><span class="kc">yes</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">RESERVED</span> <span class="nx">@identifierError</span> <span class="nx">id</span> <span class="nx">unless</span> <span class="nx">forcedIdentifier</span> <span class="nv">id = </span><span class="nx">COFFEE_ALIASES</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">hasOwnProperty</span> <span class="nx">id</span> <span class="nv">tag = </span><span class="k">switch</span> <span class="nx">id</span> <span class="k">when</span> <span class="s1">&#39;!&#39;</span> <span class="k">then</span> <span class="s1">&#39;UNARY&#39;</span> <span class="k">when</span> <span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="s1">&#39;!=&#39;</span> <span class="k">then</span> <span class="s1">&#39;COMPARE&#39;</span> <span class="k">when</span> <span class="s1">&#39;&amp;&amp;&#39;</span><span class="p">,</span> <span class="s1">&#39;||&#39;</span> <span class="k">then</span> <span class="s1">&#39;LOGIC&#39;</span> <span class="k">when</span> <span class="s1">&#39;true&#39;</span><span class="p">,</span> <span class="s1">&#39;false&#39;</span><span class="p">,</span> <span class="s1">&#39;null&#39;</span><span class="p">,</span> <span class="s1">&#39;undefined&#39;</span> <span class="k">then</span> <span class="s1">&#39;BOOL&#39;</span> <span class="k">when</span> <span class="s1">&#39;break&#39;</span><span class="p">,</span> <span class="s1">&#39;continue&#39;</span><span class="p">,</span> <span class="s1">&#39;debugger&#39;</span> <span class="k">then</span> <span class="s1">&#39;STATEMENT&#39;</span> <span class="k">else</span> <span class="nx">tag</span> <span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">id</span> <span class="nx">@token</span> <span class="s1">&#39;:&#39;</span><span class="p">,</span> <span class="s1">&#39;:&#39;</span> <span class="k">if</span> <span class="nx">colon</span> <span class="nx">input</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Matches numbers, including decimals, hex, and exponential notation. Be careful not to interfere with ranges-in-progress.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">numberToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">NUMBER</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nv">number = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="nx">@token</span> <span class="s1">&#39;NUMBER&#39;</span><span class="p">,</span> <span class="nx">number</span> <span class="nx">number</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Matches strings, including multi-line strings. Ensures that quotation marks are balanced within the string's contents, and within nested interpolations.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">stringToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">switch</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span> <span class="mi">0</span> <span class="k">when</span> <span class="s2">&quot;&#39;&quot;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">SIMPLESTR</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nx">@token</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nv">string = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">replace</span> <span class="nx">MULTILINER</span><span class="p">,</span> <span class="s1">&#39;\\\n&#39;</span> <span class="k">when</span> <span class="s1">&#39;&quot;&#39;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">string = </span><span class="nx">@balancedString</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="p">[[</span><span class="s1">&#39;&quot;&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;#{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">]]</span> <span class="k">if</span> <span class="mi">0</span> <span class="o">&lt;</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;#{&#39;</span><span class="p">,</span> <span class="mi">1</span> <span class="nx">@interpolateString</span> <span class="nx">string</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span> <span class="k">else</span> <span class="nx">@token</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="nx">@escapeLines</span> <span class="nx">string</span> <span class="k">else</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">string</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Matches heredocs, adjusting indentation to the correct level, as heredocs preserve whitespace, but ignore indentation to the left.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">heredocToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">HEREDOC</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nv">heredoc = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="nv">quote = </span><span class="nx">heredoc</span><span class="p">.</span><span class="nx">charAt</span> <span class="mi">0</span> <span class="nv">doc = </span><span class="nx">@sanitizeHeredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">quote</span><span class="o">:</span> <span class="nx">quote</span><span class="p">,</span> <span class="nx">indent</span><span class="o">:</span> <span class="kc">null</span> <span class="k">if</span> <span class="nx">quote</span> <span class="o">is</span> <span class="s1">&#39;&quot;&#39;</span> <span class="o">and</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;#{&#39;</span> <span class="nx">@interpolateString</span> <span class="nx">doc</span><span class="p">,</span> <span class="nx">heredoc</span><span class="o">:</span> <span class="kc">yes</span> <span class="k">else</span> <span class="nx">@token</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="nx">@makeString</span> <span class="nx">doc</span><span class="p">,</span> <span class="nx">quote</span><span class="p">,</span> <span class="kc">yes</span> <span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">heredoc</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nx">heredoc</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Matches and consumes comments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">commentToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">COMMENT</span> <span class="p">[</span><span class="nx">comment</span><span class="p">,</span> <span class="nx">here</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span> <span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">comment</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="k">if</span> <span class="nx">here</span> <span class="nx">@token</span> <span class="s1">&#39;HERECOMMENT&#39;</span><span class="p">,</span> <span class="nx">@sanitizeHeredoc</span> <span class="nx">here</span><span class="p">,</span> <span class="nx">herecomment</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">indent</span><span class="o">:</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">@indent</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span> <span class="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">jsToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;`&#39;</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">JSTOKEN</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nx">@token</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nv">script = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">slice</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span> <span class="nx">script</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Matches regular expression literals. Lexing regular expressions is difficult to distinguish from division, so we borrow some basic heuristics from JavaScript and Ruby.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">regexToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">&#39;/&#39;</span> <span class="k">return</span> <span class="nx">@heregexToken</span> <span class="nx">match</span> <span class="k">if</span> <span class="nv">match = </span><span class="nx">HEREGEX</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span> <span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">(</span><span class="k">if</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="k">then</span> <span class="nx">NOT_REGEX</span> <span class="k">else</span> <span class="nx">NOT_SPACED_REGEX</span><span class="p">))</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">REGEX</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="p">[</span><span class="nx">regex</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span> <span class="nx">@token</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="k">if</span> <span class="nx">regex</span> <span class="o">is</span> <span class="s1">&#39;//&#39;</span> <span class="k">then</span> <span class="s1">&#39;/(?:)/&#39;</span> <span class="k">else</span> <span class="nx">regex</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Matches multiline extended regular expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">heregexToken</span><span class="o">:</span> <span class="p">(</span><span class="nx">match</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">heregex</span><span class="p">,</span> <span class="nx">body</span><span class="p">,</span> <span class="nx">flags</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span> <span class="k">if</span> <span class="mi">0</span> <span class="o">&gt;</span> <span class="nx">body</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;#{&#39;</span> <span class="nv">re = </span><span class="nx">body</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">HEREGEX_OMIT</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\//g</span><span class="p">,</span> <span class="s1">&#39;\\/&#39;</span><span class="p">)</span> <span class="nx">@token</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="s2">&quot;/#{ re or &#39;(?:)&#39; }/#{flags}&quot;</span> <span class="k">return</span> <span class="nx">heregex</span><span class="p">.</span><span class="nx">length</span> <span class="nx">@token</span> <span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;RegExp&#39;</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;CALL_START&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">]</span> <span class="nv">tokens = </span><span class="p">[]</span> <span class="k">for</span> <span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span> <span class="k">in</span> <span class="nx">@interpolateString</span><span class="p">(</span><span class="nx">body</span><span class="p">,</span> <span class="nx">regex</span><span class="o">:</span> <span class="kc">yes</span><span class="p">)</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;TOKENS&#39;</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">value</span><span class="p">...</span> <span class="k">else</span> <span class="k">continue</span> <span class="nx">unless</span> <span class="nv">value = </span><span class="nx">value</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">HEREGEX_OMIT</span><span class="p">,</span> <span class="s1">&#39;&#39;</span> <span class="nv">value = </span><span class="nx">value</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\\/g</span><span class="p">,</span> <span class="s1">&#39;\\\\&#39;</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="nx">@makeString</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">,</span> <span class="kc">yes</span><span class="p">)]</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;+&#39;</span><span class="p">]</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&quot;&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;+&#39;</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;STRING&#39;</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">tokens</span><span class="p">...</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">,</span> <span class="s1">&#39;,&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span> <span class="o">+</span> <span class="nx">flags</span> <span class="o">+</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="nx">flags</span> <span class="nx">@token</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span> <span class="nx">heregex</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which. If we can detect that the current line is continued onto the the next line, then the newline is suppressed:</p> <pre><code>elements .each( ... ) .map( ... ) </code></pre> <p>Keeps track of the level of indentation, because a single outdent token can close multiple indents, so we need to know how far in we happen to be.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">lineToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">MULTI_DENT</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="nv">indent = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">indent</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">,</span> <span class="mi">1</span> <span class="nv">size = </span><span class="nx">indent</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">lastIndexOf</span> <span class="s1">&#39;\n&#39;</span> <span class="nv">noNewlines = </span><span class="nx">@unfinished</span><span class="p">()</span> <span class="k">if</span> <span class="nx">size</span> <span class="o">-</span> <span class="nx">@indebt</span> <span class="o">is</span> <span class="nx">@indent</span> <span class="k">if</span> <span class="nx">noNewlines</span> <span class="k">then</span> <span class="nx">@suppressNewlines</span><span class="p">()</span> <span class="k">else</span> <span class="nx">@newlineToken</span><span class="p">()</span> <span class="k">return</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span> <span class="k">if</span> <span class="nx">size</span> <span class="o">&gt;</span> <span class="nx">@indent</span> <span class="k">if</span> <span class="nx">noNewlines</span> <span class="vi">@indebt = </span><span class="nx">size</span> <span class="o">-</span> <span class="nx">@indent</span> <span class="nx">@suppressNewlines</span><span class="p">()</span> <span class="k">return</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span> <span class="nv">diff = </span><span class="nx">size</span> <span class="o">-</span> <span class="nx">@indent</span> <span class="o">+</span> <span class="nx">@outdebt</span> <span class="nx">@token</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="nx">diff</span> <span class="nx">@indents</span><span class="p">.</span><span class="nx">push</span> <span class="nx">diff</span> <span class="vi">@outdebt = @indebt = </span><span class="mi">0</span> <span class="k">else</span> <span class="vi">@indebt = </span><span class="mi">0</span> <span class="nx">@outdentToken</span> <span class="nx">@indent</span> <span class="o">-</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">noNewlines</span> <span class="vi">@indent = </span><span class="nx">size</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Record an outdent token or multiple tokens, if we happen to be moving back inwards past several recorded indents.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">outdentToken</span><span class="o">:</span> <span class="p">(</span><span class="nx">moveOut</span><span class="p">,</span> <span class="nx">noNewlines</span><span class="p">,</span> <span class="nx">close</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="k">while</span> <span class="nx">moveOut</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="nv">len = </span><span class="nx">@indents</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">@indents</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="o">is</span> <span class="kc">undefined</span> <span class="nv">moveOut = </span><span class="mi">0</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">@indents</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="o">is</span> <span class="nx">@outdebt</span> <span class="nx">moveOut</span> <span class="o">-=</span> <span class="nx">@outdebt</span> <span class="vi">@outdebt = </span><span class="mi">0</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">@indents</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="o">&lt;</span> <span class="nx">@outdebt</span> <span class="nx">@outdebt</span> <span class="o">-=</span> <span class="nx">@indents</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="nx">moveOut</span> <span class="o">-=</span> <span class="nx">@indents</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="k">else</span> <span class="nv">dent = </span><span class="nx">@indents</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="o">-</span> <span class="nx">@outdebt</span> <span class="nx">moveOut</span> <span class="o">-=</span> <span class="nx">dent</span> <span class="vi">@outdebt = </span><span class="mi">0</span> <span class="nx">@token</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="nx">dent</span> <span class="nx">@outdebt</span> <span class="o">-=</span> <span class="nx">moveOut</span> <span class="k">if</span> <span class="nx">dent</span> <span class="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span> <span class="o">or</span> <span class="nx">noNewlines</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>Matches and consumes non-meaningful whitespace. Tag the previous token as being "spaced", because there are some cases where it makes a difference.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">whitespaceToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="p">(</span><span class="nv">match = </span><span class="nx">WHITESPACE</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="nv">nline = </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;\n&#39;</span><span class="p">)</span> <span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span> <span class="nx">prev</span><span class="p">[</span><span class="k">if</span> <span class="nx">match</span> <span class="k">then</span> <span class="s1">&#39;spaced&#39;</span> <span class="k">else</span> <span class="s1">&#39;newLine&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">prev</span> <span class="k">if</span> <span class="nx">match</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">length</span> <span class="k">else</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Generate a newline token. Consecutive newlines get merged together.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">newlineToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>Use a <code>\</code> at a line-ending to suppress the newline. The slash is removed here once its job is done.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">suppressNewlines</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;\\&#39;</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>We treat all other single characters as a token. E.g.: <code>( ) , . !</code> Multi-character operators are also literal tokens, so that Jison can assign the proper order of operations. There are some symbols that we tag specially here. <code>;</code> and newlines are both treated as a <code>TERMINATOR</code>, we distinguish parentheses that indicate a method call from regular parentheses, and so on.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">literalToken</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="k">if</span> <span class="nv">match = </span><span class="nx">OPERATOR</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span> <span class="p">[</span><span class="nx">value</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span> <span class="nx">@tagParameters</span><span class="p">()</span> <span class="k">if</span> <span class="nx">CODE</span><span class="p">.</span><span class="nx">test</span> <span class="nx">value</span> <span class="k">else</span> <span class="nv">value = </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span> <span class="mi">0</span> <span class="nv">tag = </span><span class="nx">value</span> <span class="nv">prev = </span><span class="nx">last<