/documentation/docs/lexer.html
HTML | 2024 lines | 1865 code | 159 blank | 0 comment | 0 complexity | 9c4487192ff7778f37ad5ad37144c273 MD5 | raw file
- <!DOCTYPE html>
- <html>
- <head>
- <title>lexer.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>lexer.coffee</h1>
- </div>
- </li>
-
-
-
- <li id="section-1">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-1">¶</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, locationData]
- </code></pre><p>where locationData is {first_line, first_column, last_line, last_column}, which is a
- format that can be fed directly into <a href="http://github.com/zaach/jison">Jison</a>. These
- are read by jison in the <code>parser.lexer</code> function defined in coffee-script.coffee.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>
- {Rewriter, INVERSES} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./rewriter'</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 need.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>{count, starts, compact, repeat, invertLiterate,
- 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>
- <h2 id="the-lexer-class">The Lexer Class</h2>
- </div>
-
- </li>
-
-
- <li id="section-4">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-4">¶</a>
- </div>
-
- </div>
-
- </li>
-
-
- <li id="section-5">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-5">¶</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>
- </div>
-
- <div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Lexer = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Lexer</span></span></pre></div></div>
-
- </li>
-
-
- <li id="section-6">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-6">¶</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>.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">tokenize</span>: <span class="hljs-function"><span class="hljs-params">(code, opts = {})</span> -></span>
- <span class="hljs-property">@literate</span> = opts.literate <span class="hljs-comment"># Are we lexing literate CoffeeScript?</span>
- <span class="hljs-property">@indent</span> = <span class="hljs-number">0</span> <span class="hljs-comment"># The current indentation level.</span>
- <span class="hljs-property">@baseIndent</span> = <span class="hljs-number">0</span> <span class="hljs-comment"># The overall minimum indentation level</span>
- <span class="hljs-property">@indebt</span> = <span class="hljs-number">0</span> <span class="hljs-comment"># The over-indentation at the current level.</span>
- <span class="hljs-property">@outdebt</span> = <span class="hljs-number">0</span> <span class="hljs-comment"># The under-outdentation at the current level.</span>
- <span class="hljs-property">@indents</span> = [] <span class="hljs-comment"># The stack of all current indentation levels.</span>
- <span class="hljs-property">@ends</span> = [] <span class="hljs-comment"># The stack for pairing up tokens.</span>
- <span class="hljs-property">@tokens</span> = [] <span class="hljs-comment"># Stream of parsed tokens in the form `['TYPE', value, location data]`.</span>
- <span class="hljs-property">@seenFor</span> = <span class="hljs-literal">no</span> <span class="hljs-comment"># Used to recognize FORIN and FOROF tokens.</span>
- <span class="hljs-property">@chunkLine</span> =
- opts.line <span class="hljs-keyword">or</span> <span class="hljs-number">0</span> <span class="hljs-comment"># The start line for the current @chunk.</span>
- <span class="hljs-property">@chunkColumn</span> =
- opts.column <span class="hljs-keyword">or</span> <span class="hljs-number">0</span> <span class="hljs-comment"># The start column of the current @chunk.</span>
- code = <span class="hljs-property">@clean</span> code <span class="hljs-comment"># The stripped, cleaned original source code.</span></pre></div></div>
-
- </li>
-
-
- <li id="section-7">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-7">¶</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>
- </div>
-
- <div class="content"><div class='highlight'><pre> i = <span class="hljs-number">0</span>
- <span class="hljs-keyword">while</span> <span class="hljs-property">@chunk</span> = code[i..]
- consumed = \
- <span class="hljs-property">@identifierToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@commentToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@whitespaceToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@lineToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@stringToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@numberToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@regexToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@jsToken</span>() <span class="hljs-keyword">or</span>
- <span class="hljs-property">@literalToken</span>()</pre></div></div>
-
- </li>
-
-
- <li id="section-8">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-8">¶</a>
- </div>
- <p>Update position</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> [<span class="hljs-property">@chunkLine</span>, <span class="hljs-property">@chunkColumn</span>] = <span class="hljs-property">@getLineAndColumnFromChunk</span> consumed
- i += consumed
- <span class="hljs-keyword">return</span> {<span class="hljs-property">@tokens</span>, <span class="hljs-attribute">index</span>: i} <span class="hljs-keyword">if</span> opts.untilBalanced <span class="hljs-keyword">and</span> <span class="hljs-property">@ends</span>.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- <span class="hljs-property">@closeIndentation</span>()
- <span class="hljs-property">@error</span> <span class="hljs-string">"missing <span class="hljs-subst">#{end.tag}</span>"</span>, end.origin[<span class="hljs-number">2</span>] <span class="hljs-keyword">if</span> end = <span class="hljs-property">@ends</span>.pop()
- <span class="hljs-keyword">return</span> <span class="hljs-property">@tokens</span> <span class="hljs-keyword">if</span> opts.rewrite <span class="hljs-keyword">is</span> <span class="hljs-literal">off</span>
- (<span class="hljs-keyword">new</span> Rewriter).rewrite <span class="hljs-property">@tokens</span></pre></div></div>
-
- </li>
-
-
- <li id="section-9">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-9">¶</a>
- </div>
- <p>Preprocess the code to remove leading and trailing whitespace, carriage
- returns, etc. If we’re lexing literate CoffeeScript, strip external Markdown
- by removing all lines that aren’t indented by at least four spaces or a tab.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">clean</span>: <span class="hljs-function"><span class="hljs-params">(code)</span> -></span>
- code = code.slice(<span class="hljs-number">1</span>) <span class="hljs-keyword">if</span> code.charCodeAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> BOM
- code = code.replace(<span class="hljs-regexp">/\r/g</span>, <span class="hljs-string">''</span>).replace TRAILING_SPACES, <span class="hljs-string">''</span>
- <span class="hljs-keyword">if</span> WHITESPACE.test code
- code = <span class="hljs-string">"\n<span class="hljs-subst">#{code}</span>"</span>
- <span class="hljs-property">@chunkLine</span>--
- code = invertLiterate code <span class="hljs-keyword">if</span> <span class="hljs-property">@literate</span>
- code</pre></div></div>
-
- </li>
-
-
- <li id="section-10">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-10">¶</a>
- </div>
- <h2 id="tokenizers">Tokenizers</h2>
- </div>
-
- </li>
-
-
- <li id="section-11">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-11">¶</a>
- </div>
-
- </div>
-
- </li>
-
-
- <li id="section-12">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-12">¶</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>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">identifierToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = IDENTIFIER.exec <span class="hljs-property">@chunk</span>
- [input, id, colon] = match</pre></div></div>
-
- </li>
-
-
- <li id="section-13">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-13">¶</a>
- </div>
- <p>Preserve length of id for location data</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> idLength = id.length
- poppedToken = <span class="hljs-literal">undefined</span>
- <span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">'own'</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'FOR'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'OWN'</span>, id
- <span class="hljs-keyword">return</span> id.length
- <span class="hljs-keyword">if</span> id <span class="hljs-keyword">is</span> <span class="hljs-string">'from'</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'YIELD'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'FROM'</span>, id
- <span class="hljs-keyword">return</span> id.length
- [..., prev] = <span class="hljs-property">@tokens</span>
- forcedIdentifier = colon <span class="hljs-keyword">or</span> prev? <span class="hljs-keyword">and</span>
- (prev[<span class="hljs-number">0</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-keyword">or</span>
- <span class="hljs-keyword">not</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'@'</span>)
- tag = <span class="hljs-string">'IDENTIFIER'</span>
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> forcedIdentifier <span class="hljs-keyword">and</span> (id <span class="hljs-keyword">in</span> JS_KEYWORDS <span class="hljs-keyword">or</span> id <span class="hljs-keyword">in</span> COFFEE_KEYWORDS)
- tag = id.toUpperCase()
- <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'WHEN'</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">in</span> LINE_BREAK
- tag = <span class="hljs-string">'LEADING_WHEN'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'FOR'</span>
- <span class="hljs-property">@seenFor</span> = <span class="hljs-literal">yes</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'UNLESS'</span>
- tag = <span class="hljs-string">'IF'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> UNARY
- tag = <span class="hljs-string">'UNARY'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> RELATION
- <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">isnt</span> <span class="hljs-string">'INSTANCEOF'</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@seenFor</span>
- tag = <span class="hljs-string">'FOR'</span> + tag
- <span class="hljs-property">@seenFor</span> = <span class="hljs-literal">no</span>
- <span class="hljs-keyword">else</span>
- tag = <span class="hljs-string">'RELATION'</span>
- <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'!'</span>
- poppedToken = <span class="hljs-property">@tokens</span>.pop()
- id = <span class="hljs-string">'!'</span> + id
- <span class="hljs-keyword">if</span> id <span class="hljs-keyword">in</span> JS_FORBIDDEN
- <span class="hljs-keyword">if</span> forcedIdentifier
- tag = <span class="hljs-string">'IDENTIFIER'</span>
- id = <span class="hljs-keyword">new</span> String id
- id.reserved = <span class="hljs-literal">yes</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> id <span class="hljs-keyword">in</span> RESERVED
- <span class="hljs-property">@error</span> <span class="hljs-string">"reserved word '<span class="hljs-subst">#{id}</span>'"</span>, <span class="hljs-attribute">length</span>: id.length
- <span class="hljs-keyword">unless</span> forcedIdentifier
- <span class="hljs-keyword">if</span> id <span class="hljs-keyword">in</span> COFFEE_ALIASES
- alias = id
- id = COFFEE_ALIAS_MAP[id]
- tag = <span class="hljs-keyword">switch</span> id
- <span class="hljs-keyword">when</span> <span class="hljs-string">'!'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'UNARY'</span>
- <span class="hljs-keyword">when</span> <span class="hljs-string">'=='</span>, <span class="hljs-string">'!='</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'COMPARE'</span>
- <span class="hljs-keyword">when</span> <span class="hljs-string">'&&'</span>, <span class="hljs-string">'||'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'LOGIC'</span>
- <span class="hljs-keyword">when</span> <span class="hljs-string">'true'</span>, <span class="hljs-string">'false'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'BOOL'</span>
- <span class="hljs-keyword">when</span> <span class="hljs-string">'break'</span>, <span class="hljs-string">'continue'</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'STATEMENT'</span>
- <span class="hljs-keyword">else</span> tag
- tagToken = <span class="hljs-property">@token</span> tag, id, <span class="hljs-number">0</span>, idLength
- tagToken.origin = [tag, alias, tagToken[<span class="hljs-number">2</span>]] <span class="hljs-keyword">if</span> alias
- tagToken.variable = <span class="hljs-keyword">not</span> forcedIdentifier
- <span class="hljs-keyword">if</span> poppedToken
- [tagToken[<span class="hljs-number">2</span>].first_line, tagToken[<span class="hljs-number">2</span>].first_column] =
- [poppedToken[<span class="hljs-number">2</span>].first_line, poppedToken[<span class="hljs-number">2</span>].first_column]
- <span class="hljs-keyword">if</span> colon
- colonOffset = input.lastIndexOf <span class="hljs-string">':'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">':'</span>, <span class="hljs-string">':'</span>, colonOffset, colon.length
- input.length</pre></div></div>
-
- </li>
-
-
- <li id="section-14">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-14">¶</a>
- </div>
- <p>Matches numbers, including decimals, hex, and exponential notation.
- Be careful not to interfere with ranges-in-progress.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">numberToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = NUMBER.exec <span class="hljs-property">@chunk</span>
- number = match[<span class="hljs-number">0</span>]
- lexedLength = number.length
- <span class="hljs-keyword">if</span> <span class="hljs-regexp">/^0[BOX]/</span>.test number
- <span class="hljs-property">@error</span> <span class="hljs-string">"radix prefix in '<span class="hljs-subst">#{number}</span>' must be lowercase"</span>, <span class="hljs-attribute">offset</span>: <span class="hljs-number">1</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-regexp">/E/</span>.test(number) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-regexp">/^0x/</span>.test number
- <span class="hljs-property">@error</span> <span class="hljs-string">"exponential notation in '<span class="hljs-subst">#{number}</span>' must be indicated with a lowercase 'e'"</span>,
- <span class="hljs-attribute">offset</span>: number.indexOf(<span class="hljs-string">'E'</span>)
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-regexp">/^0\d*[89]/</span>.test number
- <span class="hljs-property">@error</span> <span class="hljs-string">"decimal literal '<span class="hljs-subst">#{number}</span>' must not be prefixed with '0'"</span>, <span class="hljs-attribute">length</span>: lexedLength
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-regexp">/^0\d+/</span>.test number
- <span class="hljs-property">@error</span> <span class="hljs-string">"octal literal '<span class="hljs-subst">#{number}</span>' must be prefixed with '0o'"</span>, <span class="hljs-attribute">length</span>: lexedLength
- <span class="hljs-keyword">if</span> octalLiteral = <span class="hljs-regexp">/^0o([0-7]+)/</span>.exec number
- number = <span class="hljs-string">'0x'</span> + parseInt(octalLiteral[<span class="hljs-number">1</span>], <span class="hljs-number">8</span>).toString <span class="hljs-number">16</span>
- <span class="hljs-keyword">if</span> binaryLiteral = <span class="hljs-regexp">/^0b([01]+)/</span>.exec number
- number = <span class="hljs-string">'0x'</span> + parseInt(binaryLiteral[<span class="hljs-number">1</span>], <span class="hljs-number">2</span>).toString <span class="hljs-number">16</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'NUMBER'</span>, number, <span class="hljs-number">0</span>, lexedLength
- lexedLength</pre></div></div>
-
- </li>
-
-
- <li id="section-15">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-15">¶</a>
- </div>
- <p>Matches strings, including multi-line strings, as well as heredocs, with or without
- interpolation.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">stringToken</span>:<span class="hljs-function"> -></span>
- [quote] = STRING_START.exec(<span class="hljs-property">@chunk</span>) || []
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> quote
- regex = <span class="hljs-keyword">switch</span> quote
- <span class="hljs-keyword">when</span> <span class="hljs-string">"'"</span> <span class="hljs-keyword">then</span> STRING_SINGLE
- <span class="hljs-keyword">when</span> <span class="hljs-string">'"'</span> <span class="hljs-keyword">then</span> STRING_DOUBLE
- <span class="hljs-keyword">when</span> <span class="hljs-string">"'''"</span> <span class="hljs-keyword">then</span> HEREDOC_SINGLE
- <span class="hljs-keyword">when</span> <span class="hljs-string">'"""'</span> <span class="hljs-keyword">then</span> HEREDOC_DOUBLE
- heredoc = quote.length <span class="hljs-keyword">is</span> <span class="hljs-number">3</span>
- {tokens, <span class="hljs-attribute">index</span>: end} = <span class="hljs-property">@matchWithInterpolations</span> regex, quote
- $ = tokens.length - <span class="hljs-number">1</span>
- delimiter = quote.charAt(<span class="hljs-number">0</span>)
- <span class="hljs-keyword">if</span> heredoc</pre></div></div>
-
- </li>
-
-
- <li id="section-16">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-16">¶</a>
- </div>
- <p>Find the smallest indentation. It will be removed from all lines later.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> indent = <span class="hljs-literal">null</span>
- doc = (token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token, i <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'NEOSTRING'</span>).join <span class="hljs-string">'#{}'</span>
- <span class="hljs-keyword">while</span> match = HEREDOC_INDENT.exec doc
- attempt = match[<span class="hljs-number">1</span>]
- indent = attempt <span class="hljs-keyword">if</span> indent <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">or</span> <span class="hljs-number">0</span> < attempt.length < indent.length
- indentRegex = <span class="hljs-regexp">/// ^<span class="hljs-subst">#{indent}</span> ///</span>gm <span class="hljs-keyword">if</span> indent
- <span class="hljs-property">@mergeInterpolationTokens</span> tokens, {delimiter}, <span class="hljs-function"><span class="hljs-params">(value, i)</span> =></span>
- value = <span class="hljs-property">@formatString</span> value
- value = value.replace LEADING_BLANK_LINE, <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- value = value.replace TRAILING_BLANK_LINE, <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> $
- value = value.replace indentRegex, <span class="hljs-string">''</span> <span class="hljs-keyword">if</span> indentRegex
- value
- <span class="hljs-keyword">else</span>
- <span class="hljs-property">@mergeInterpolationTokens</span> tokens, {delimiter}, <span class="hljs-function"><span class="hljs-params">(value, i)</span> =></span>
- value = <span class="hljs-property">@formatString</span> value
- value = value.replace SIMPLE_STRING_OMIT, <span class="hljs-function"><span class="hljs-params">(match, offset)</span> -></span>
- <span class="hljs-keyword">if</span> (i <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> offset <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>) <span class="hljs-keyword">or</span>
- (i <span class="hljs-keyword">is</span> $ <span class="hljs-keyword">and</span> offset + match.length <span class="hljs-keyword">is</span> value.length)
- <span class="hljs-string">''</span>
- <span class="hljs-keyword">else</span>
- <span class="hljs-string">' '</span>
- value
- end</pre></div></div>
-
- </li>
-
-
- <li id="section-17">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-17">¶</a>
- </div>
- <p>Matches and consumes comments.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">commentToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = <span class="hljs-property">@chunk</span>.match COMMENT
- [comment, here] = match
- <span class="hljs-keyword">if</span> here
- <span class="hljs-keyword">if</span> match = HERECOMMENT_ILLEGAL.exec comment
- <span class="hljs-property">@error</span> <span class="hljs-string">"block comments cannot contain <span class="hljs-subst">#{match[<span class="hljs-number">0</span>]}</span>"</span>,
- <span class="hljs-attribute">offset</span>: match.index, <span class="hljs-attribute">length</span>: match[<span class="hljs-number">0</span>].length
- <span class="hljs-keyword">if</span> here.indexOf(<span class="hljs-string">'\n'</span>) >= <span class="hljs-number">0</span>
- here = here.replace <span class="hljs-regexp">/// \n <span class="hljs-subst">#{repeat <span class="hljs-string">' '</span>, <span class="hljs-property">@indent</span>}</span> ///</span>g, <span class="hljs-string">'\n'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'HERECOMMENT'</span>, here, <span class="hljs-number">0</span>, comment.length
- comment.length</pre></div></div>
-
- </li>
-
-
- <li id="section-18">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-18">¶</a>
- </div>
- <p>Matches JavaScript interpolated directly into the source via backticks.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">jsToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@chunk</span>.charAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'`'</span> <span class="hljs-keyword">and</span> match = JSTOKEN.exec <span class="hljs-property">@chunk</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'JS'</span>, (script = match[<span class="hljs-number">0</span>])[<span class="hljs-number">1.</span>..-<span class="hljs-number">1</span>], <span class="hljs-number">0</span>, script.length
- script.length</pre></div></div>
-
- </li>
-
-
- <li id="section-19">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-19">¶</a>
- </div>
- <p>Matches regular expression literals, as well as multiline extended ones.
- Lexing regular expressions is difficult to distinguish from division, so we
- borrow some basic heuristics from JavaScript and Ruby.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">regexToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">switch</span>
- <span class="hljs-keyword">when</span> match = REGEX_ILLEGAL.exec <span class="hljs-property">@chunk</span>
- <span class="hljs-property">@error</span> <span class="hljs-string">"regular expressions cannot begin with <span class="hljs-subst">#{match[<span class="hljs-number">2</span>]}</span>"</span>,
- <span class="hljs-attribute">offset</span>: match.index + match[<span class="hljs-number">1</span>].length
- <span class="hljs-keyword">when</span> match = <span class="hljs-property">@matchWithInterpolations</span> HEREGEX, <span class="hljs-string">'///'</span>
- {tokens, index} = match
- <span class="hljs-keyword">when</span> match = REGEX.exec <span class="hljs-property">@chunk</span>
- [regex, body, closed] = match
- <span class="hljs-property">@validateEscapes</span> body, <span class="hljs-attribute">isRegex</span>: <span class="hljs-literal">yes</span>, <span class="hljs-attribute">offsetInChunk</span>: <span class="hljs-number">1</span>
- index = regex.length
- [..., prev] = <span class="hljs-property">@tokens</span>
- <span class="hljs-keyword">if</span> prev
- <span class="hljs-keyword">if</span> prev.spaced <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> closed <span class="hljs-keyword">or</span> POSSIBLY_DIVISION.test regex
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> NOT_REGEX
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
- <span class="hljs-property">@error</span> <span class="hljs-string">'missing / (unclosed regex)'</span> <span class="hljs-keyword">unless</span> closed
- <span class="hljs-keyword">else</span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
- [flags] = REGEX_FLAGS.exec <span class="hljs-property">@chunk</span>[index..]
- end = index + flags.length
- origin = <span class="hljs-property">@makeToken</span> <span class="hljs-string">'REGEX'</span>, <span class="hljs-literal">null</span>, <span class="hljs-number">0</span>, end
- <span class="hljs-keyword">switch</span>
- <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> VALID_FLAGS.test flags
- <span class="hljs-property">@error</span> <span class="hljs-string">"invalid regular expression flags <span class="hljs-subst">#{flags}</span>"</span>, <span class="hljs-attribute">offset</span>: index, <span class="hljs-attribute">length</span>: flags.length
- <span class="hljs-keyword">when</span> regex <span class="hljs-keyword">or</span> tokens.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
- body ?= <span class="hljs-property">@formatHeregex</span> tokens[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>]
- <span class="hljs-property">@token</span> <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@makeDelimitedLiteral</span> body, delimiter: <span class="hljs-string">'/'</span>}</span><span class="hljs-subst">#{flags}</span>"</span>, <span class="hljs-number">0</span>, end, origin
- <span class="hljs-keyword">else</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'REGEX_START'</span>, <span class="hljs-string">'('</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, origin
- <span class="hljs-property">@token</span> <span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'RegExp'</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'CALL_START'</span>, <span class="hljs-string">'('</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>
- <span class="hljs-property">@mergeInterpolationTokens</span> tokens, {<span class="hljs-attribute">delimiter</span>: <span class="hljs-string">'"'</span>, <span class="hljs-attribute">double</span>: <span class="hljs-literal">yes</span>}, <span class="hljs-property">@formatHeregex</span>
- <span class="hljs-keyword">if</span> flags
- <span class="hljs-property">@token</span> <span class="hljs-string">','</span>, <span class="hljs-string">','</span>, index, <span class="hljs-number">0</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'"'</span> + flags + <span class="hljs-string">'"'</span>, index, flags.length
- <span class="hljs-property">@token</span> <span class="hljs-string">')'</span>, <span class="hljs-string">')'</span>, end, <span class="hljs-number">0</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'REGEX_END'</span>, <span class="hljs-string">')'</span>, end, <span class="hljs-number">0</span>
- end</pre></div></div>
-
- </li>
-
-
- <li id="section-20">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-20">¶</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 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>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">lineToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> match = MULTI_DENT.exec <span class="hljs-property">@chunk</span>
- indent = match[<span class="hljs-number">0</span>]
- <span class="hljs-property">@seenFor</span> = <span class="hljs-literal">no</span>
- size = indent.length - <span class="hljs-number">1</span> - indent.lastIndexOf <span class="hljs-string">'\n'</span>
- noNewlines = <span class="hljs-property">@unfinished</span>()
- <span class="hljs-keyword">if</span> size - <span class="hljs-property">@indebt</span> <span class="hljs-keyword">is</span> <span class="hljs-property">@indent</span>
- <span class="hljs-keyword">if</span> noNewlines <span class="hljs-keyword">then</span> <span class="hljs-property">@suppressNewlines</span>() <span class="hljs-keyword">else</span> <span class="hljs-property">@newlineToken</span> <span class="hljs-number">0</span>
- <span class="hljs-keyword">return</span> indent.length
- <span class="hljs-keyword">if</span> size > <span class="hljs-property">@indent</span>
- <span class="hljs-keyword">if</span> noNewlines
- <span class="hljs-property">@indebt</span> = size - <span class="hljs-property">@indent</span>
- <span class="hljs-property">@suppressNewlines</span>()
- <span class="hljs-keyword">return</span> indent.length
- <span class="hljs-keyword">unless</span> <span class="hljs-property">@tokens</span>.length
- <span class="hljs-property">@baseIndent</span> = <span class="hljs-property">@indent</span> = size
- <span class="hljs-keyword">return</span> indent.length
- diff = size - <span class="hljs-property">@indent</span> + <span class="hljs-property">@outdebt</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'INDENT'</span>, diff, indent.length - size, size
- <span class="hljs-property">@indents</span>.push diff
- <span class="hljs-property">@ends</span>.push {<span class="hljs-attribute">tag</span>: <span class="hljs-string">'OUTDENT'</span>}
- <span class="hljs-property">@outdebt</span> = <span class="hljs-property">@indebt</span> = <span class="hljs-number">0</span>
- <span class="hljs-property">@indent</span> = size
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> size < <span class="hljs-property">@baseIndent</span>
- <span class="hljs-property">@error</span> <span class="hljs-string">'missing indentation'</span>, <span class="hljs-attribute">offset</span>: indent.length
- <span class="hljs-keyword">else</span>
- <span class="hljs-property">@indebt</span> = <span class="hljs-number">0</span>
- <span class="hljs-property">@outdentToken</span> <span class="hljs-property">@indent</span> - size, noNewlines, indent.length
- indent.length</pre></div></div>
-
- </li>
-
-
- <li id="section-21">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-21">¶</a>
- </div>
- <p>Record an outdent token or multiple tokens, if we happen to be moving back
- inwards past several recorded indents. Sets new @indent value.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">outdentToken</span>: <span class="hljs-function"><span class="hljs-params">(moveOut, noNewlines, outdentLength)</span> -></span>
- decreasedIndent = <span class="hljs-property">@indent</span> - moveOut
- <span class="hljs-keyword">while</span> moveOut > <span class="hljs-number">0</span>
- lastIndent = <span class="hljs-property">@indents</span>[<span class="hljs-property">@indents</span>.length - <span class="hljs-number">1</span>]
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> lastIndent
- moveOut = <span class="hljs-number">0</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> lastIndent <span class="hljs-keyword">is</span> <span class="hljs-property">@outdebt</span>
- moveOut -= <span class="hljs-property">@outdebt</span>
- <span class="hljs-property">@outdebt</span> = <span class="hljs-number">0</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> lastIndent < <span class="hljs-property">@outdebt</span>
- <span class="hljs-property">@outdebt</span> -= lastIndent
- moveOut -= lastIndent
- <span class="hljs-keyword">else</span>
- dent = <span class="hljs-property">@indents</span>.pop() + <span class="hljs-property">@outdebt</span>
- <span class="hljs-keyword">if</span> outdentLength <span class="hljs-keyword">and</span> <span class="hljs-property">@chunk</span>[outdentLength] <span class="hljs-keyword">in</span> INDENTABLE_CLOSERS
- decreasedIndent -= dent - moveOut
- moveOut = dent
- <span class="hljs-property">@outdebt</span> = <span class="hljs-number">0</span></pre></div></div>
-
- </li>
-
-
- <li id="section-22">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-22">¶</a>
- </div>
- <p>pair might call outdentToken, so preserve decreasedIndent</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-property">@pair</span> <span class="hljs-string">'OUTDENT'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'OUTDENT'</span>, moveOut, <span class="hljs-number">0</span>, outdentLength
- moveOut -= dent
- <span class="hljs-property">@outdebt</span> -= moveOut <span class="hljs-keyword">if</span> dent
- <span class="hljs-property">@tokens</span>.pop() <span class="hljs-keyword">while</span> <span class="hljs-property">@value</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'TERMINATOR'</span>, <span class="hljs-string">'\n'</span>, outdentLength, <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">or</span> noNewlines
- <span class="hljs-property">@indent</span> = decreasedIndent
- <span class="hljs-keyword">this</span></pre></div></div>
-
- </li>
-
-
- <li id="section-23">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-23">¶</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>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">whitespaceToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> (match = WHITESPACE.exec <span class="hljs-property">@chunk</span>) <span class="hljs-keyword">or</span>
- (nline = <span class="hljs-property">@chunk</span>.charAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'\n'</span>)
- [..., prev] = <span class="hljs-property">@tokens</span>
- prev[<span class="hljs-keyword">if</span> match <span class="hljs-keyword">then</span> <span class="hljs-string">'spaced'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'newLine'</span>] = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> prev
- <span class="hljs-keyword">if</span> match <span class="hljs-keyword">then</span> match[<span class="hljs-number">0</span>].length <span class="hljs-keyword">else</span> <span class="hljs-number">0</span></pre></div></div>
-
- </li>
-
-
- <li id="section-24">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-24">¶</a>
- </div>
- <p>Generate a newline token. Consecutive newlines get merged together.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">newlineToken</span>: <span class="hljs-function"><span class="hljs-params">(offset)</span> -></span>
- <span class="hljs-property">@tokens</span>.pop() <span class="hljs-keyword">while</span> <span class="hljs-property">@value</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
- <span class="hljs-property">@token</span> <span class="hljs-string">'TERMINATOR'</span>, <span class="hljs-string">'\n'</span>, offset, <span class="hljs-number">0</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span>
- <span class="hljs-keyword">this</span></pre></div></div>
-
- </li>
-
-
- <li id="section-25">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-25">¶</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>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">suppressNewlines</span>:<span class="hljs-function"> -></span>
- <span class="hljs-property">@tokens</span>.pop() <span class="hljs-keyword">if</span> <span class="hljs-property">@value</span>() <span class="hljs-keyword">is</span> <span class="hljs-string">'\\'</span>
- <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>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>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">literalToken</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">if</span> match = OPERATOR.exec <span class="hljs-property">@chunk</span>
- [value] = match
- <span class="hljs-property">@tagParameters</span>() <span class="hljs-keyword">if</span> CODE.test value
- <span class="hljs-keyword">else</span>
- value = <span class="hljs-property">@chunk</span>.charAt <span class="hljs-number">0</span>
- tag = value
- [..., prev] = <span class="hljs-property">@tokens</span>
- <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'='</span> <span class="hljs-keyword">and</span> prev
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> prev[<span class="hljs-number">1</span>].reserved <span class="hljs-keyword">and</span> prev[<span class="hljs-number">1</span>] <span class="hljs-keyword">in</span> JS_FORBIDDEN
- prev = prev.origin <span class="hljs-keyword">if</span> prev.origin
- <span class="hljs-property">@error</span> <span class="hljs-string">"reserved word '<span class="hljs-subst">#{prev[<span class="hljs-number">1</span>]}</span>' can't be assigned"</span>, prev[<span class="hljs-number">2</span>]
- <span class="hljs-keyword">if</span> prev[<span class="hljs-number">1</span>] <span class="hljs-keyword">in</span> [<span class="hljs-string">'||'</span>, <span class="hljs-string">'&&'</span>]
- prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'COMPOUND_ASSIGN'</span>
- prev[<span class="hljs-number">1</span>] += <span class="hljs-string">'='</span>
- <span class="hljs-keyword">return</span> value.length
- <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">';'</span>
- <span class="hljs-property">@seenFor</span> = <span class="hljs-literal">no</span>
- tag = <span class="hljs-string">'TERMINATOR'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> MATH <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'MATH'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> COMPARE <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'COMPARE'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> COMPOUND_ASSIGN <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'COMPOUND_ASSIGN'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> UNARY <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'UNARY'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> UNARY_MATH <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'UNARY_MATH'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> SHIFT <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'SHIFT'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">in</span> LOGIC <span class="hljs-keyword">or</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">and</span> prev?.spaced <span class="hljs-keyword">then</span> tag = <span class="hljs-string">'LOGIC'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prev <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> prev.spaced
- <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'('</span> <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> CALLABLE
- prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'FUNC_EXIST'</span> <span class="hljs-keyword">if</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span>
- tag = <span class="hljs-string">'CALL_START'</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-string">'['</span> <span class="hljs-keyword">and</span> prev[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> INDEXABLE
- tag = <span class="hljs-string">'INDEX_START'</span>
- <span class="hljs-keyword">switch</span> prev[<span class="hljs-number">0</span>]
- <span class="hljs-keyword">when</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">then</span> prev[<span class="hljs-number">0</span>] = <span class="hljs-string">'INDEX_SOAK'</span>
- token = <span class="hljs-property">@makeToken</span> tag, value
- <span class="hljs-keyword">switch</span> value
- <span class="hljs-keyword">when</span> <span class="hljs-string">'('</span>, <span class="hljs-string">'{'</span>, <span class="hljs-string">'['</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@ends</span>.push {<span class="hljs-attribute">tag</span>: INVERSES[value], <span class="hljs-attribute">origin</span>: token}
- <span class="hljs-keyword">when</span> <span class="hljs-string">')'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">']'</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@pair</span> value
- <span class="hljs-property">@tokens</span>.push token
- value.length</pre></div></div>
-
- </li>
-
-
- <li id="section-27">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-27">¶</a>
- </div>
- <h2 id="token-manipulators">Token Manipulators</h2>
- </div>
-
- </li>
-
-
- <li id="section-28">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-28">¶</a>
- </div>
-
- </div>
-
- </li>
-
-
- <li id="section-29">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-29">¶</a>
- </div>
- <p>A source of ambiguity in our grammar used to be parameter lists in function
- definitions versus argument lists in function calls. Walk backwards, tagging
- parameters specially in order to make things easier for the parser.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">tagParameters</span>:<span class="hljs-function"> -></span>
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@tag</span>() <span class="hljs-keyword">isnt</span> <span class="hljs-string">')'</span>
- stack = []
- {tokens} = <span class="hljs-keyword">this</span>
- i = tokens.length
- tokens[--i][<span class="hljs-number">0</span>] = <span class="hljs-string">'PARAM_END'</span>
- <span class="hljs-keyword">while</span> tok = tokens[--i]
- <span class="hljs-keyword">switch</span> tok[<span class="hljs-number">0</span>]
- <span class="hljs-keyword">when</span> <span class="hljs-string">')'</span>
- stack.push tok
- <span class="hljs-keyword">when</span> <span class="hljs-string">'('</span>, <span class="hljs-string">'CALL_START'</span>
- <span class="hljs-keyword">if</span> stack.length <span class="hljs-keyword">then</span> stack.pop()
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> tok[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'('</span>
- tok[<span class="hljs-number">0</span>] = <span class="hljs-string">'PARAM_START'</span>
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
- <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
- <span class="hljs-keyword">this</span></pre></div></div>
-
- </li>
-
-
- <li id="section-30">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-30">¶</a>
- </div>
- <p>Close up all remaining open blocks at the end of the file.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">closeIndentation</span>:<span class="hljs-function"> -></span>
- <span class="hljs-property">@outdentToken</span> <span class="hljs-property">@indent</span></pre></div></div>
-
- </li>
-
-
- <li id="section-31">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-31">¶</a>
- </div>
- <p>Match the contents of a delimited token and expand variables and expressions
- inside it using Ruby-like notation for substitution of arbitrary
- expressions.</p>
- <pre><code><span class="hljs-string">"Hello <span class="hljs-subst">#{name.capitalize()}</span>."</span>
- </code></pre><p>If it encounters an interpolation, this method will recursively create a new
- Lexer and tokenize until the <code>{</code> of <code>#{</code> is balanced with a <code>}</code>.</p>
- <ul>
- <li><code>regex</code> matches the contents of a token (but not <code>delimiter</code>, and not
- <code>#{</code> if interpolations are desired).</li>
- <li><code>delimiter</code> is the delimiter of the token. Examples are <code>'</code>, <code>"</code>, <code>'''</code>,
- <code>"""</code> and <code>///</code>.</li>
- </ul>
- <p>This method allows us to have strings within interpolations within strings,
- ad infinitum.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">matchWithInterpolations</span>: <span class="hljs-function"><span class="hljs-params">(regex, delimiter)</span> -></span>
- tokens = []
- offsetInChunk = delimiter.length
- <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@chunk</span>[...offsetInChunk] <span class="hljs-keyword">is</span> delimiter
- str = <span class="hljs-property">@chunk</span>[offsetInChunk..]
- <span class="hljs-keyword">loop</span>
- [strPart] = regex.exec str
- <span class="hljs-property">@validateEscapes</span> strPart, {<span class="hljs-attribute">isRegex</span>: delimiter.charAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'/'</span>, offsetInChunk}</pre></div></div>
-
- </li>
-
-
- <li id="section-32">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-32">¶</a>
- </div>
- <p>Push a fake ‘NEOSTRING’ token, which will get turned into a real string later.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> tokens.push <span class="hljs-property">@makeToken</span> <span class="hljs-string">'NEOSTRING'</span>, strPart, offsetInChunk
- str = str[strPart.length..]
- offsetInChunk += strPart.length
- <span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> str[..<span class="hljs-number">.2</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'#{'</span></pre></div></div>
-
- </li>
-
-
- <li id="section-33">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-33">¶</a>
- </div>
- <p>The <code>1</code>s are to remove the <code>#</code> in <code>#{</code>.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> [line, column] = <span class="hljs-property">@getLineAndColumnFromChunk</span> offsetInChunk + <span class="hljs-number">1</span>
- {<span class="hljs-attribute">tokens</span>: nested, index} =
- <span class="hljs-keyword">new</span> Lexer().tokenize str[<span class="hljs-number">1.</span>.], <span class="hljs-attribute">line</span>: line, <span class="hljs-attribute">column</span>: column, <span class="hljs-attribute">untilBalanced</span>: <span class="hljs-literal">on</span></pre></div></div>
-
- </li>
-
-
- <li id="section-34">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-34">¶</a>
- </div>
- <p>Skip the trailing <code>}</code>.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> index += <span class="hljs-number">1</span></pre></div></div>
-
- </li>
-
-
- <li id="section-35">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-35">¶</a>
- </div>
- <p>Turn the leading and trailing <code>{</code> and <code>}</code> into parentheses. Unnecessary
- parentheses will be removed later.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> [open, ..., close] = nested
- open[<span class="hljs-number">0</span>] = open[<span class="hljs-number">1</span>] = <span class="hljs-string">'('</span>
- close[<span class="hljs-number">0</span>] = close[<span class="hljs-number">1</span>] = <span class="hljs-string">')'</span>
- close.origin = [<span class="hljs-string">''</span>, <span class="hljs-string">'end of interpolation'</span>, close[<span class="hljs-number">2</span>]]</pre></div></div>
-
- </li>
-
-
- <li id="section-36">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-36">¶</a>
- </div>
- <p>Remove leading ‘TERMINATOR’ (if any).</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> nested.splice <span class="hljs-number">1</span>, <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> nested[<span class="hljs-number">1</span>]?[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span></pre></div></div>
-
- </li>
-
-
- <li id="section-37">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-37">¶</a>
- </div>
- <p>Push a fake ‘TOKENS’ token, which will get turned into real tokens later.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> tokens.push [<span class="hljs-string">'TOKENS'</span>, nested]
- str = str[index..]
- offsetInChunk += index
- <span class="hljs-keyword">unless</span> str[...delimiter.length] <span class="hljs-keyword">is</span> delimiter
- <span class="hljs-property">@error</span> <span class="hljs-string">"missing <span class="hljs-subst">#{delimiter}</span>"</span>, <span class="hljs-attribute">length</span>: delimiter.length
- [firstToken, ..., lastToken] = tokens
- firstToken[<span class="hljs-number">2</span>].first_column -= delimiter.length
- lastToken[<span class="hljs-number">2</span>].last_column += delimiter.length
- lastToken[<span class="hljs-number">2</span>].last_column -= <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> lastToken[<span class="hljs-number">1</span>].length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- {tokens, <span class="hljs-attribute">index</span>: offsetInChunk + delimiter.length}</pre></div></div>
-
- </li>
-
-
- <li id="section-38">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-38">¶</a>
- </div>
- <p>Merge the array <code>tokens</code> of the fake token types ‘TOKENS’ and ‘NEOSTRING’
- (as returned by <code>matchWithInterpolations</code>) into the token stream. The value
- of ‘NEOSTRING’s are converted using <code>fn</code> and turned into strings using
- <code>options</code> first.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">mergeInterpolationTokens</span>: <span class="hljs-function"><span class="hljs-params">(tokens, options, fn)</span> -></span>
- <span class="hljs-keyword">if</span> tokens.length > <span class="hljs-number">1</span>
- lparen = <span class="hljs-property">@token</span> <span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'('</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>
- firstIndex = <span class="hljs-property">@tokens</span>.length
- <span class="hljs-keyword">for</span> token, i <span class="hljs-keyword">in</span> tokens
- [tag, value] = token
- <span class="hljs-keyword">switch</span> tag
- <span class="hljs-keyword">when</span> <span class="hljs-string">'TOKENS'</span></pre></div></div>
-
- </li>
-
-
- <li id="section-39">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-39">¶</a>
- </div>
- <p>Optimize out empty interpolations (an empty pair of parentheses).</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> value.length <span class="hljs-keyword">is</span> <span class="hljs-number">2</span></pre></div></div>
-
- </li>
-
-
- <li id="section-40">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-40">¶</a>
- </div>
- <p>Push all the tokens in the fake ‘TOKENS’ token. These already have
- sane location data.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> locationToken = value[<span class="hljs-number">0</span>]
- tokensToPush = value
- <span class="hljs-keyword">when</span> <span class="hljs-string">'NEOSTRING'</span></pre></div></div>
-
- </li>
-
-
- <li id="section-41">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-41">¶</a>
- </div>
- <p>Convert ‘NEOSTRING’ into ‘STRING’.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> converted = fn token[<span class="hljs-number">1</span>], i</pre></div></div>
-
- </li>
-
-
- <li id="section-42">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-42">¶</a>
- </div>
- <p>Optimize out empty strings. We ensure that the tokens stream always
- starts with a string token, though, to make sure that the result
- really is a string.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> converted.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- firstEmptyStringIndex = <span class="hljs-property">@tokens</span>.length
- <span class="hljs-keyword">else</span>
- <span class="hljs-keyword">continue</span></pre></div></div>
-
- </li>
-
-
- <li id="section-43">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-43">¶</a>
- </div>
- <p>However, there is one case where we can optimize away a starting
- empty string.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> firstEmptyStringIndex?
- <span class="hljs-property">@tokens</span>.splice firstEmptyStringIndex, <span class="hljs-number">2</span> <span class="hljs-comment"># Remove empty string and the plus.</span>
- token[<span class="hljs-number">0</span>] = <span class="hljs-string">'STRING'</span>
- token[<span class="hljs-number">1</span>] = <span class="hljs-property">@makeDelimitedLiteral</span> converted, options
- locationToken = token
- tokensToPush = [token]
- <span class="hljs-keyword">if</span> <span class="hljs-property">@tokens</span>.length > firstIndex</pre></div></div>
-
- </li>
-
-
- <li id="section-44">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-44">¶</a>
- </div>
- <p>Create a 0-length “+” token.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> plusToken = <span class="hljs-property">@token</span> <span class="hljs-string">'+'</span>, <span class="hljs-string">'+'</span>
- plusToken[<span class="hljs-number">2</span>] =
- <span class="hljs-attribute">first_line</span>: locationToken[<span class="hljs-number">2</span>].first_line
- <span class="hljs-attribute">first_column</span>: locationToken[<span class="hljs-number">2</span>].first_column
- <span class="hljs-attribute">last_line</span>: locationToken[<span class="hljs-number">2</span>].first_line
- <span class="hljs-attribute">last_column</span>: locationToken[<span class="hljs-number">2</span>].first_column
- <span class="hljs-property">@tokens</span>.push tokensToPush...
- <span class="hljs-keyword">if</span> lparen
- [..., lastToken] = tokens
- lparen.origin = [<span class="hljs-string">'STRING'</span>, <span class="hljs-literal">null</span>,
- <span class="hljs-attribute">first_line</span>: lparen[<span class="hljs-number">2</span>].first_line
- <span class="hljs-attribute">first_column</span>: lparen[<span class="hljs-number">2</span>].first_column
- <span class="hljs-attribute">last_line</span>: lastToken[<span class="hljs-number">2</span>].last_line
- <span class="hljs-attribute">last_column</span>: lastToken[<span class="hljs-number">2</span>].last_column
- ]
- rparen = <span class="hljs-property">@token</span> <span class="hljs-string">'STRING_END'</span>, <span class="hljs-string">')'</span>
- rparen[<span class="hljs-number">2</span>] =
- <span class="hljs-attribute">first_line</span>: lastToken[<span class="hljs-number">2</span>].last_line
- <span class="hljs-attribute">first_column</span>: lastToken[<span class="hljs-number">2</span>].last_column
- <span class="hljs-attribute">last_line</span>: lastToken[<span class="hljs-number">2</span>].last_line
- <span class="hljs-attribute">last_column</span>: lastToken[<span class="hljs-number">2</span>].last_column</pre></div></div>
-
- </li>
-
-
- <li id="section-45">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-45">¶</a>
- </div>
- <p>Pairs up a closing token, ensuring that all listed pairs of tokens are
- correctly balanced throughout the course of the token stream.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">pair</span>: <span class="hljs-function"><span class="hljs-params">(tag)</span> -></span>
- [..., prev] = <span class="hljs-property">@ends</span>
- <span class="hljs-keyword">unless</span> tag <span class="hljs-keyword">is</span> wanted = prev?.tag
- <span class="hljs-property">@error</span> <span class="hljs-string">"unmatched <span class="hljs-subst">#{tag}</span>"</span> <span class="hljs-keyword">unless</span> <span class="hljs-string">'OUTDENT'</span> <span class="hljs-keyword">is</span> wanted</pre></div></div>
-
- </li>
-
-
- <li id="section-46">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-46">¶</a>
- </div>
- <p>Auto-close INDENT to support syntax like this:</p>
- <pre><code>el.click<span class="hljs-function"><span class="hljs-params">((event) ->
- el.hide())</span></span>
- </code></pre>
- </div>
-
- <div class="content"><div class='highlight'><pre> [..., lastIndent] = <span class="hljs-property">@indents</span>
- <span class="hljs-property">@outdentToken</span> lastIndent, <span class="hljs-literal">true</span>
- <span class="hljs-keyword">return</span> <span class="hljs-property">@pair</span> tag
- <span class="hljs-property">@ends</span>.pop()</pre></div></div>
-
- </li>
-
-
- <li id="section-47">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-47">¶</a>
- </div>
- <h2 id="helpers">Helpers</h2>
- </div>
-
- </li>
-
-
- <li id="section-48">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-48">¶</a>
- </div>
-
- </div>
-
- </li>
-
-
- <li id="section-49">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-49">¶</a>
- </div>
- <p>Returns the line and column number from an offset into the current chunk.</p>
- <p><code>offset</code> is a number of characters into @chunk.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">getLineAndColumnFromChunk</span>: <span class="hljs-function"><span class="hljs-params">(offset)</span> -></span>
- <span class="hljs-keyword">if</span> offset <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
- <span class="hljs-keyword">return</span> [<span class="hljs-property">@chunkLine</span>, <span class="hljs-property">@chunkColumn</span>]
- <span class="hljs-keyword">if</span> offset >= <span class="hljs-property">@chunk</span>.length
- string = <span class="hljs-property">@chunk</span>
- <span class="hljs-keyword">else</span>
- string = <span class="hljs-property">@chunk</span>[..offset-<span class="hljs-number">1</span>]
- lineCount = count string, <span class="hljs-string">'\n'</span>
- column = <span class="hljs-property">@chunkColumn</span>
- <span class="hljs-keyword">if</span> lineCount > <span class="hljs-number">0</span>
- [..., lastLine] = string.split <span class="hljs-string">'\n'</span>
- column = lastLine.length
- <span class="hljs-keyword">else</span>
- column += string.length
- [<span class="hljs-property">@chunkLine</span> + lineCount, column]</pre></div></div>
-
- </li>
-
-
- <li id="section-50">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-50">¶</a>
- </div>
- <p>Same as “token”, exception this just returns the token without adding it
- to the results.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">makeToken</span>: <span class="hljs-function"><span class="hljs-params">(tag, value, offsetInChunk = <span class="hljs-number">0</span>, length = value.length)</span> -></span>
- locationData = {}
- [locationData.first_line, locationData.first_column] =
- <span class="hljs-property">@getLineAndColumnFromChunk</span> offsetInChunk</pre></div></div>
-
- </li>
-
-
- <li id="section-51">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-51">¶</a>
- </div>
- <p>Use length - 1 for the final offset - we’re supplying the last_line and the last_column,
- so if last_column == first_column, then we’re looking at a character of length 1.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> lastCharacter = Math.max <span class="hljs-number">0</span>, length - <span class="hljs-number">1</span>
- [locationData.last_line, locationData.last_column] =
- <span class="hljs-property">@getLineAndColumnFromChunk</span> offsetInChunk + lastCharacter
- token = [tag, value, locationData]
- token</pre></div></div>
-
- </li>
-
-
- <li id="section-52">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-52">¶</a>
- </div>
- <p>Add a token to the results.
- <code>offset</code> is the offset into the current @chunk where the token starts.
- <code>length</code> is the length of the token in the @chunk, after the offset. If
- not specified, the length of <code>value</code> will be used.</p>
- <p>Returns the new token.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">token</span>: <span class="hljs-function"><span class="hljs-params">(tag, value, offsetInChunk, length, origin)</span> -></span>
- token = <span class="hljs-property">@makeToken</span> tag, value, offsetInChunk, length
- token.origin = origin <span class="hljs-keyword">if</span> origin
- <span class="hljs-property">@tokens</span>.push token
- token</pre></div></div>
-
- </li>
-
-
- <li id="section-53">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-53">¶</a>
- </div>
- <p>Peek at the last tag in the token stream.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">tag</span>:<span class="hljs-function"> -></span>
- [..., token] = <span class="hljs-property">@tokens</span>
- token?[<span class="hljs-number">0</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-54">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-54">¶</a>
- </div>
- <p>Peek at the last value in the token stream.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">value</span>:<span class="hljs-function"> -></span>
- [..., token] = <span class="hljs-property">@tokens</span>
- token?[<span class="hljs-number">1</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-55">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-55">¶</a>
- </div>
- <p>Are we in the midst of an unfinished expression?</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">unfinished</span>:<span class="hljs-function"> -></span>
- LINE_CONTINUER.test(<span class="hljs-property">@chunk</span>) <span class="hljs-keyword">or</span>
- <span class="hljs-property">@tag</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">'UNARY'</span>, <span class="hljs-string">'MATH'</span>, <span class="hljs-string">'UNARY_MATH'</span>, <span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>, <span class="hljs-string">'YIELD'</span>,
- <span class="hljs-string">'**'</span>, <span class="hljs-string">'SHIFT'</span>, <span class="hljs-string">'RELATION'</span>, <span class="hljs-string">'COMPARE'</span>, <span class="hljs-string">'LOGIC'</span>, <span class="hljs-string">'THROW'</span>, <span class="hljs-string">'EXTENDS'</span>]
- <span class="hljs-attribute">formatString</span>: <span class="hljs-function"><span class="hljs-params">(str)</span> -></span>
- str.replace STRING_OMIT, <span class="hljs-string">'$1'</span>
- <span class="hljs-attribute">formatHeregex</span>: <span class="hljs-function"><span class="hljs-params">(str)</span> -></span>
- str.replace HEREGEX_OMIT, <span class="hljs-string">'$1$2'</span></pre></div></div>
-
- </li>
-
-
- <li id="section-56">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-56">¶</a>
- </div>
- <p>Validates escapes in strings and regexes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">validateEscapes</span>: <span class="hljs-function"><span class="hljs-params">(str, options = {})</span> -></span>
- match = INVALID_ESCAPE.exec str
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> match
- [[], before, octal, hex, unicode] = match
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> options.isRegex <span class="hljs-keyword">and</span> octal <span class="hljs-keyword">and</span> octal.charAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'0'</span>
- message =
- <span class="hljs-keyword">if</span> octal
- <span class="hljs-string">"octal escape sequences are not allowed"</span>
- <span class="hljs-keyword">else</span>
- <span class="hljs-string">"invalid escape sequence"</span>
- invalidEscape = <span class="hljs-string">"\\<span class="hljs-subst">#{octal <span class="hljs-keyword">or</span> hex <span class="hljs-keyword">or</span> unicode}</span>"</span>
- <span class="hljs-property">@error</span> <span class="hljs-string">"<span class="hljs-subst">#{message}</span> <span class="hljs-subst">#{invalidEscape}</span>"</span>,
- <span class="hljs-attribute">offset</span>: (options.offsetInChunk ? <span class="hljs-number">0</span>) + match.index + before.length
- <span class="hljs-attribute">length</span>: invalidEscape.length</pre></div></div>
-
- </li>
-
-
- <li id="section-57">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-57">¶</a>
- </div>
- <p>Constructs a string or regex by escaping certain characters.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">makeDelimitedLiteral</span>: <span class="hljs-function"><span class="hljs-params">(body, options = {})</span> -></span>
- body = <span class="hljs-string">'(?:)'</span> <span class="hljs-keyword">if</span> body <span class="hljs-keyword">is</span> <span class="hljs-string">''</span> <span class="hljs-keyword">and</span> options.delimiter <span class="hljs-keyword">is</span> <span class="hljs-string">'/'</span>
- regex = <span class="hljs-regexp">///
- (\\\\) <span class="hljs-comment"># escaped backslash</span>
- | (\\0(?=[1-7])) <span class="hljs-comment"># nul character mistaken as octal escape</span>
- | \\?(<span class="hljs-subst">#{options.delimiter}</span>) <span class="hljs-comment"># (possibly escaped) delimiter</span>
- | \\?(?: (\n)|(\r)|(\u2028)|(\u2029) ) <span class="hljs-comment"># (possibly escaped) newlines</span>
- | (\\.) <span class="hljs-comment"># other escapes</span>
- ///</span>g
- body = body.replace regex, <span class="hljs-function"><span class="hljs-params">(match, backslash, nul, delimiter, lf, cr, ls, ps, other)</span> -></span> <span class="hljs-keyword">switch</span></pre></div></div>
-
- </li>
-
-
- <li id="section-58">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-58">¶</a>
- </div>
- <p>Ignore escaped backslashes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">when</span> backslash <span class="hljs-keyword">then</span> (<span class="hljs-keyword">if</span> options.double <span class="hljs-keyword">then</span> backslash + backslash <span class="hljs-keyword">else</span> backslash)
- <span class="hljs-keyword">when</span> nul <span class="hljs-keyword">then</span> <span class="hljs-string">'\\x00'</span>
- <span class="hljs-keyword">when</span> delimiter <span class="hljs-keyword">then</span> <span class="hljs-string">"\\<span class="hljs-subst">#{delimiter}</span>"</span>
- <span class="hljs-keyword">when</span> lf <span class="hljs-keyword">then</span> <span class="hljs-string">'\\n'</span>
- <span class="hljs-keyword">when</span> cr <span class="hljs-keyword">then</span> <span class="hljs-string">'\\r'</span>
- <span class="hljs-keyword">when</span> ls <span class="hljs-keyword">then</span> <span class="hljs-string">'\\u2028'</span>
- <span class="hljs-keyword">when</span> ps <span class="hljs-keyword">then</span> <span class="hljs-string">'\\u2029'</span>
- <span class="hljs-keyword">when</span> other <span class="hljs-keyword">then</span> (<span class="hljs-keyword">if</span> options.double <span class="hljs-keyword">then</span> <span class="hljs-string">"\\<span class="hljs-subst">#{other}</span>"</span> <span class="hljs-keyword">else</span> other)
- <span class="hljs-string">"<span class="hljs-subst">#{options.delimiter}</span><span class="hljs-subst">#{body}</span><span class="hljs-subst">#{options.delimiter}</span>"</span></pre></div></div>
-
- </li>
-
-
- <li id="section-59">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-59">¶</a>
- </div>
- <p>Throws an error at either a given offset from the current chunk or at the
- location of a token (<code>token[2]</code>).</p>
- </div>
-
- <div class="content"><div class='highlight'><pre> <span class="hljs-attribute">error</span>: <span class="hljs-function"><span class="hljs-params">(message, options = {})</span> -></span>
- location =
- <span class="hljs-keyword">if</span> <span class="hljs-string">'first_line'</span> <span class="hljs-keyword">of</span> options
- options
- <span class="hljs-keyword">else</span>
- [first_line, first_column] = <span class="hljs-property">@getLineAndColumnFromChunk</span> options.offset ? <span class="hljs-number">0</span>
- {first_line, first_column, <span class="hljs-attribute">last_column</span>: first_column + (options.length ? <span class="hljs-number">1</span>) - <span class="hljs-number">1</span>}
- throwSyntaxError message, location</pre></div></div>
-
- </li>
-
-
- <li id="section-60">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-60">¶</a>
- </div>
- <h2 id="constants">Constants</h2>
- </div>
-
- </li>
-
-
- <li id="section-61">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-61">¶</a>
- </div>
-
- </div>
-
- </li>
-
-
- <li id="section-62">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-62">¶</a>
- </div>
- <p>Keywords that CoffeeScript shares in common with JavaScript.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>JS_KEYWORDS = [
- <span class="hljs-string">'true'</span>, <span class="hljs-string">'false'</span>, <span class="hljs-string">'null'</span>, <span class="hljs-string">'this'</span>
- <span class="hljs-string">'new'</span>, <span class="hljs-string">'delete'</span>, <span class="hljs-string">'typeof'</span>, <span class="hljs-string">'in'</span>, <span class="hljs-string">'instanceof'</span>
- <span class="hljs-string">'return'</span>, <span class="hljs-string">'throw'</span>, <span class="hljs-string">'break'</span>, <span class="hljs-string">'continue'</span>, <span class="hljs-string">'debugger'</span>, <span class="hljs-string">'yield'</span>
- <span class="hljs-string">'if'</span>, <span class="hljs-string">'else'</span>, <span class="hljs-string">'switch'</span>, <span class="hljs-string">'for'</span>, <span class="hljs-string">'while'</span>, <span class="hljs-string">'do'</span>, <span class="hljs-string">'try'</span>, <span class="hljs-string">'catch'</span>, <span class="hljs-string">'finally'</span>
- <span class="hljs-string">'class'</span>, <span class="hljs-string">'extends'</span>, <span class="hljs-string">'super'</span>
- ]</pre></div></div>
-
- </li>
-
-
- <li id="section-63">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-63">¶</a>
- </div>
- <p>CoffeeScript-only keywords.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>COFFEE_KEYWORDS = [<span class="hljs-string">'undefined'</span>, <span class="hljs-string">'then'</span>, <span class="hljs-string">'unless'</span>, <span class="hljs-string">'until'</span>, <span class="hljs-string">'loop'</span>, <span class="hljs-string">'of'</span>, <span class="hljs-string">'by'</span>, <span class="hljs-string">'when'</span>]
- COFFEE_ALIAS_MAP =
- <span class="hljs-keyword">and</span> : <span class="hljs-string">'&&'</span>
- <span class="hljs-keyword">or</span> : <span class="hljs-string">'||'</span>
- <span class="hljs-keyword">is</span> : <span class="hljs-string">'=='</span>
- <span class="hljs-keyword">isnt</span> : <span class="hljs-string">'!='</span>
- <span class="hljs-keyword">not</span> : <span class="hljs-string">'!'</span>
- <span class="hljs-literal">yes</span> : <span class="hljs-string">'true'</span>
- <span class="hljs-literal">no</span> : <span class="hljs-string">'false'</span>
- <span class="hljs-literal">on</span> : <span class="hljs-string">'true'</span>
- <span class="hljs-literal">off</span> : <span class="hljs-string">'false'</span>
- COFFEE_ALIASES = (key <span class="hljs-keyword">for</span> key <span class="hljs-keyword">of</span> COFFEE_ALIAS_MAP)
- COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES</pre></div></div>
-
- </li>
-
-
- <li id="section-64">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-64">¶</a>
- </div>
- <p>The list of keywords that are reserved by JavaScript, but not used, or are
- used by CoffeeScript internally. We throw an error when these are encountered,
- to avoid having a JavaScript error at runtime.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>RESERVED = [
- <span class="hljs-string">'case'</span>, <span class="hljs-string">'default'</span>, <span class="hljs-string">'function'</span>, <span class="hljs-string">'var'</span>, <span class="hljs-string">'void'</span>, <span class="hljs-string">'with'</span>, <span class="hljs-string">'const'</span>, <span class="hljs-string">'let'</span>, <span class="hljs-string">'enum'</span>
- <span class="hljs-string">'export'</span>, <span class="hljs-string">'import'</span>, <span class="hljs-string">'native'</span>, <span class="hljs-string">'implements'</span>, <span class="hljs-string">'interface'</span>, <span class="hljs-string">'package'</span>, <span class="hljs-string">'private'</span>
- <span class="hljs-string">'protected'</span>, <span class="hljs-string">'public'</span>, <span class="hljs-string">'static'</span>
- ]
- STRICT_PROSCRIBED = [<span class="hljs-string">'arguments'</span>, <span class="hljs-string">'eval'</span>, <span class="hljs-string">'yield*'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-65">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-65">¶</a>
- </div>
- <p>The superset of both JavaScript keywords and reserved words, none of which may
- be used as identifiers or properties.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
- <span class="hljs-built_in">exports</span>.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
- <span class="hljs-built_in">exports</span>.STRICT_PROSCRIBED = STRICT_PROSCRIBED</pre></div></div>
-
- </li>
-
-
- <li id="section-66">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-66">¶</a>
- </div>
- <p>The character code of the nasty Microsoft madness otherwise known as the BOM.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>BOM = <span class="hljs-number">65279</span></pre></div></div>
-
- </li>
-
-
- <li id="section-67">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-67">¶</a>
- </div>
- <p>Token matching regexes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>IDENTIFIER = <span class="hljs-regexp">/// ^
- (?!\d)
- ( (?: (?!\s)[$\w\x7f-\uffff] )+ )
- ( [^\n\S]* : (?!:) )? <span class="hljs-comment"># Is this a property name?</span>
- ///</span>
- NUMBER = <span class="hljs-regexp">///
- ^ 0b[01]+ | <span class="hljs-comment"># binary</span>
- ^ 0o[0-7]+ | <span class="hljs-comment"># octal</span>
- ^ 0x[\da-f]+ | <span class="hljs-comment"># hex</span>
- ^ \d*\.?\d+ (?:e[+-]?\d+)? <span class="hljs-comment"># decimal</span>
- ///</span>i
- OPERATOR = <span class="hljs-regexp">/// ^ (
- ?: [-=]> <span class="hljs-comment"># function</span>
- | [-+*/%<>&|^!?=]= <span class="hljs-comment"># compound assign / compare</span>
- | >>>=? <span class="hljs-comment"># zero-fill right shift</span>
- | ([-+:])\1 <span class="hljs-comment"># doubles</span>
- | ([&|<>*/%])\2=? <span class="hljs-comment"># logic / shift / power / floor division / modulo</span>
- | \?(\.|::) <span class="hljs-comment"># soak access</span>
- | \.{2,3} <span class="hljs-comment"># range or splat</span>
- ) ///</span>
- WHITESPACE = <span class="hljs-regexp">/^[^\n\S]+/</span>
- COMMENT = <span class="hljs-regexp">/^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/</span>
- CODE = <span class="hljs-regexp">/^[-=]>/</span>
- MULTI_DENT = <span class="hljs-regexp">/^(?:\n[^\n\S]*)+/</span>
- JSTOKEN = <span class="hljs-regexp">/^`[^\\`]*(?:\\.[^\\`]*)*`/</span></pre></div></div>
-
- </li>
-
-
- <li id="section-68">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-68">¶</a>
- </div>
- <p>String-matching-regexes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>STRING_START = <span class="hljs-regexp">/^(?:'''|"""|'|")/</span>
- STRING_SINGLE = <span class="hljs-regexp">/// ^(?: [^\\'] | \\[\s\S] )* ///</span>
- STRING_DOUBLE = <span class="hljs-regexp">/// ^(?: [^\\"<span class="hljs-comment">#] | \\[\s\S] | \#(?!\{) )* ///</span>
- HEREDOC_SINGLE = ///</span> ^(?: [^\\<span class="hljs-string">'] | \\[\s\S] | '</span>(?!<span class="hljs-string">''</span>) )* <span class="hljs-regexp">///
- HEREDOC_DOUBLE = ///</span> ^(?: [^\\<span class="hljs-string">"#] | \\[\s\S] | "</span>(?!<span class="hljs-string">""</span>) | \<span class="hljs-comment">#(?!\{) )* ///</span>
- STRING_OMIT = <span class="hljs-regexp">///
- ((?:\\\\)+) <span class="hljs-comment"># consume (and preserve) an even number of backslashes</span>
- | \\[^\S\n]*\n\s* <span class="hljs-comment"># remove escaped newlines</span>
- ///</span>g
- SIMPLE_STRING_OMIT = <span class="hljs-regexp">/\s*\n\s*/g</span>
- HEREDOC_INDENT = <span class="hljs-regexp">/\n+([^\n\S]*)(?=\S)/g</span></pre></div></div>
-
- </li>
-
-
- <li id="section-69">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-69">¶</a>
- </div>
- <p>Regex-matching-regexes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>REGEX = <span class="hljs-regexp">/// ^
- / (?!/) ((
- ?: [^ [ / \n \\ ] <span class="hljs-comment"># every other thing</span>
- | \\[^\n] <span class="hljs-comment"># anything but newlines escaped</span>
- | \[ <span class="hljs-comment"># character class</span>
- (?: \\[^\n] | [^ \] \n \\ ] )*
- \]
- )*) (/)?
- ///</span>
- REGEX_FLAGS = <span class="hljs-regexp">/^\w*/</span>
- VALID_FLAGS = <span class="hljs-regexp">/^(?!.*(.).*\1)[imgy]*$/</span>
- HEREGEX = <span class="hljs-regexp">/// ^(?: [^\\/<span class="hljs-comment">#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///</span>
- HEREGEX_OMIT = ///</span>
- ((?:\\\\)+) <span class="hljs-comment"># consume (and preserve) an even number of backslashes</span>
- | \\(\s) <span class="hljs-comment"># preserve escaped whitespace</span>
- | \s+(?:<span class="hljs-comment">#.*)? # remove whitespace and comments</span>
- <span class="hljs-regexp">///g
- REGEX_ILLEGAL = ///</span> ^ ( / | <span class="hljs-regexp">/{3}\s*) (\*) /</span><span class="hljs-regexp">//</span>
- POSSIBLY_DIVISION = <span class="hljs-regexp">/// ^ /=?\s ///</span></pre></div></div>
-
- </li>
-
-
- <li id="section-70">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-70">¶</a>
- </div>
- <p>Other regexes.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>HERECOMMENT_ILLEGAL = <span class="hljs-regexp">/\*\//</span>
- LINE_CONTINUER = <span class="hljs-regexp">/// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///</span>
- INVALID_ESCAPE = <span class="hljs-regexp">///
- ( (?:^|[^\\]) (?:\\\\)* ) <span class="hljs-comment"># make sure the escape isn’t escaped</span>
- \\ (
- ?: (0[0-7]|[1-7]) <span class="hljs-comment"># octal escape</span>
- | (x(?![\da-fA-F]{2}).{0,2}) <span class="hljs-comment"># hex escape</span>
- | (u(?![\da-fA-F]{4}).{0,4}) <span class="hljs-comment"># unicode escape</span>
- )
- ///</span>
- LEADING_BLANK_LINE = <span class="hljs-regexp">/^[^\n\S]*\n/</span>
- TRAILING_BLANK_LINE = <span class="hljs-regexp">/\n[^\n\S]*$/</span>
- TRAILING_SPACES = <span class="hljs-regexp">/\s+$/</span></pre></div></div>
-
- </li>
-
-
- <li id="section-71">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-71">¶</a>
- </div>
- <p>Compound assignment tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>COMPOUND_ASSIGN = [
- <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-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-string">'^='</span>, <span class="hljs-string">'|='</span>, <span class="hljs-string">'**='</span>, <span class="hljs-string">'//='</span>, <span class="hljs-string">'%%='</span>
- ]</pre></div></div>
-
- </li>
-
-
- <li id="section-72">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-72">¶</a>
- </div>
- <p>Unary tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>UNARY = [<span class="hljs-string">'NEW'</span>, <span class="hljs-string">'TYPEOF'</span>, <span class="hljs-string">'DELETE'</span>, <span class="hljs-string">'DO'</span>]
- UNARY_MATH = [<span class="hljs-string">'!'</span>, <span class="hljs-string">'~'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-73">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-73">¶</a>
- </div>
- <p>Logical tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>LOGIC = [<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>]</pre></div></div>
-
- </li>
-
-
- <li id="section-74">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-74">¶</a>
- </div>
- <p>Bit-shifting tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>SHIFT = [<span class="hljs-string">'<<'</span>, <span class="hljs-string">'>>'</span>, <span class="hljs-string">'>>>'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-75">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-75">¶</a>
- </div>
- <p>Comparison tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>COMPARE = [<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>]</pre></div></div>
-
- </li>
-
-
- <li id="section-76">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-76">¶</a>
- </div>
- <p>Mathematical tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>MATH = [<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>]</pre></div></div>
-
- </li>
-
-
- <li id="section-77">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-77">¶</a>
- </div>
- <p>Relational tokens that are negatable with <code>not</code> prefix.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>RELATION = [<span class="hljs-string">'IN'</span>, <span class="hljs-string">'OF'</span>, <span class="hljs-string">'INSTANCEOF'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-78">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-78">¶</a>
- </div>
- <p>Boolean tokens.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>BOOL = [<span class="hljs-string">'TRUE'</span>, <span class="hljs-string">'FALSE'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-79">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-79">¶</a>
- </div>
- <p>Tokens which could legitimately be invoked or indexed. An opening
- parentheses or bracket following these tokens will be recorded as the start
- of a function invocation or indexing operation.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>CALLABLE = [<span class="hljs-string">'IDENTIFIER'</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">'THIS'</span>, <span class="hljs-string">'SUPER'</span>]
- INDEXABLE = CALLABLE.concat [
- <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_END'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_END'</span>
- <span class="hljs-string">'BOOL'</span>, <span class="hljs-string">'NULL'</span>, <span class="hljs-string">'UNDEFINED'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">'::'</span>
- ]</pre></div></div>
-
- </li>
-
-
- <li id="section-80">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-80">¶</a>
- </div>
- <p>Tokens which a regular expression will never immediately follow (except spaced
- CALLABLEs in some cases), but which a division operator can.</p>
- <p>See: <a href="http://www-archive.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions">http://www-archive.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</a></p>
- </div>
-
- <div class="content"><div class='highlight'><pre>NOT_REGEX = INDEXABLE.concat [<span class="hljs-string">'++'</span>, <span class="hljs-string">'--'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-81">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-81">¶</a>
- </div>
- <p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
- occurs at the start of a line. We disambiguate these from trailing whens to
- avoid an ambiguity in the grammar.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>LINE_BREAK = [<span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>, <span class="hljs-string">'TERMINATOR'</span>]</pre></div></div>
-
- </li>
-
-
- <li id="section-82">
- <div class="annotation">
-
- <div class="pilwrap ">
- <a class="pilcrow" href="#section-82">¶</a>
- </div>
- <p>Additional indent in front of these is ignored.</p>
- </div>
-
- <div class="content"><div class='highlight'><pre>INDENTABLE_CLOSERS = [<span class="hljs-string">')'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">']'</span>]</pre></div></div>
-
- </li>
-
- </ul>
- </div>
- </body>
- </html>