mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
1227 lines
58 KiB
HTML
1227 lines
58 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html>
|
|
<head>
|
|
<title>rewriter.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">
|
|
|
|
|
|
<a class="source" href="browser.html">
|
|
browser.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="cake.html">
|
|
cake.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="coffee-script.html">
|
|
coffee-script.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="command.html">
|
|
command.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="grammar.html">
|
|
grammar.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="helpers.html">
|
|
helpers.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="index.html">
|
|
index.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="lexer.html">
|
|
lexer.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="nodes.html">
|
|
nodes.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="optparse.html">
|
|
optparse.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="repl.html">
|
|
repl.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="rewriter.html">
|
|
rewriter.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="scope.html">
|
|
scope.litcoffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="sourcemap.html">
|
|
sourcemap.litcoffee
|
|
</a>
|
|
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
<ul class="sections">
|
|
|
|
<li id="title">
|
|
<div class="annotation">
|
|
<h1>rewriter.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 language has a good deal of optional syntax, implicit syntax,
|
|
and shorthand syntax. This can greatly complicate a grammar and bloat
|
|
the resulting parse table. Instead of making the parser handle it all, we take
|
|
a series of passes over the token stream, using this <strong>Rewriter</strong> to convert
|
|
shorthand into the unambiguous long form, add implicit indentation and
|
|
parentheses, and generally clean things up.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-2">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-2">¶</a>
|
|
</div>
|
|
<p>Create a generated token: one that exists due to a use of implicit syntax.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="function"><span class="title">generate</span></span> = (tag, value) ->
|
|
tok = [tag, value]
|
|
tok.generated = <span class="literal">yes</span>
|
|
tok</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-3">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-3">¶</a>
|
|
</div>
|
|
<p>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
|
its internal array of tokens.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">class</span> <span class="title">exports</span>.<span class="title">Rewriter</span></span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-4">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-4">¶</a>
|
|
</div>
|
|
<p>Helpful snippet for debugging:
|
|
|
|
</p>
|
|
<pre><code>console.log (t[0] + '/' + t[1] for t in @tokens).join ' '</code></pre>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-5">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-5">¶</a>
|
|
</div>
|
|
<p>Rewrite the token stream in multiple passes, one logical filter at
|
|
a time. This could certainly be changed into a single pass through the
|
|
stream, with a big ol' efficient switch, but it's much nicer to work with
|
|
like this. The order of these passes matters -- indentation must be
|
|
corrected before implicit parentheses can be wrapped around blocks of code.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> rewrite: (<span class="property">@tokens</span>) ->
|
|
<span class="property">@removeLeadingNewlines</span>()
|
|
<span class="property">@removeMidExpressionNewlines</span>()
|
|
<span class="property">@closeOpenCalls</span>()
|
|
<span class="property">@closeOpenIndexes</span>()
|
|
<span class="property">@addImplicitIndentation</span>()
|
|
<span class="property">@tagPostfixConditionals</span>()
|
|
<span class="property">@addImplicitBracesAndParens</span>()
|
|
<span class="property">@addLocationDataToGeneratedTokens</span>()
|
|
<span class="property">@tokens</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-6">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-6">¶</a>
|
|
</div>
|
|
<p>Rewrite the token stream, looking one token ahead and behind.
|
|
Allow the return value of the block to tell us how many tokens to move
|
|
forwards (or backwards) in the stream, to make sure we don't miss anything
|
|
as tokens are inserted and removed, and the stream changes length under
|
|
our feet.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> scanTokens: (block) ->
|
|
{tokens} = <span class="keyword">this</span>
|
|
i = <span class="number">0</span>
|
|
i += block.call <span class="keyword">this</span>, token, i, tokens <span class="keyword">while</span> token = tokens[i]
|
|
<span class="literal">true</span>
|
|
|
|
detectEnd: (i, condition, action) ->
|
|
{tokens} = <span class="keyword">this</span>
|
|
levels = <span class="number">0</span>
|
|
<span class="keyword">while</span> token = tokens[i]
|
|
<span class="keyword">return</span> action.call <span class="keyword">this</span>, token, i <span class="keyword">if</span> levels <span class="keyword">is</span> <span class="number">0</span> <span class="keyword">and</span> condition.call <span class="keyword">this</span>, token, i
|
|
<span class="keyword">return</span> action.call <span class="keyword">this</span>, token, i - <span class="number">1</span> <span class="keyword">if</span> <span class="keyword">not</span> token <span class="keyword">or</span> levels < <span class="number">0</span>
|
|
<span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">in</span> EXPRESSION_START
|
|
levels += <span class="number">1</span>
|
|
<span class="keyword">else</span> <span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">in</span> EXPRESSION_END
|
|
levels -= <span class="number">1</span>
|
|
i += <span class="number">1</span>
|
|
i - <span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-7">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-7">¶</a>
|
|
</div>
|
|
<p>Leading newlines would introduce an ambiguity in the grammar, so we
|
|
dispatch them here.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> removeLeadingNewlines: ->
|
|
<span class="keyword">break</span> <span class="keyword">for</span> [tag], i <span class="keyword">in</span> <span class="property">@tokens</span> <span class="keyword">when</span> tag <span class="keyword">isnt</span> <span class="string">'TERMINATOR'</span>
|
|
<span class="property">@tokens</span>.splice <span class="number">0</span>, i <span class="keyword">if</span> i</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-8">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-8">¶</a>
|
|
</div>
|
|
<p>Some blocks occur in the middle of expressions -- when we're expecting
|
|
this, remove their trailing newlines.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> removeMidExpressionNewlines: ->
|
|
<span class="property">@scanTokens</span> (token, i, tokens) ->
|
|
<span class="keyword">return</span> <span class="number">1</span> <span class="keyword">unless</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'TERMINATOR'</span> <span class="keyword">and</span> <span class="property">@tag</span>(i + <span class="number">1</span>) <span class="keyword">in</span> EXPRESSION_CLOSE
|
|
tokens.splice i, <span class="number">1</span>
|
|
<span class="number">0</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-9">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-9">¶</a>
|
|
</div>
|
|
<p>The lexer has tagged the opening parenthesis of a method call. Match it with
|
|
its paired close. We have the mis-nested outdent case included here for
|
|
calls that close on the same line, just before their outdent.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> closeOpenCalls: ->
|
|
<span class="function"><span class="title">condition</span></span> = (token, i) ->
|
|
token[<span class="number">0</span>] <span class="keyword">in</span> [<span class="string">')'</span>, <span class="string">'CALL_END'</span>] <span class="keyword">or</span>
|
|
token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'OUTDENT'</span> <span class="keyword">and</span> <span class="property">@tag</span>(i - <span class="number">1</span>) <span class="keyword">is</span> <span class="string">')'</span>
|
|
|
|
<span class="function"><span class="title">action</span></span> = (token, i) ->
|
|
<span class="property">@tokens</span>[<span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'OUTDENT'</span> <span class="keyword">then</span> i - <span class="number">1</span> <span class="keyword">else</span> i][<span class="number">0</span>] = <span class="string">'CALL_END'</span>
|
|
|
|
<span class="property">@scanTokens</span> (token, i) ->
|
|
<span class="property">@detectEnd</span> i + <span class="number">1</span>, condition, action <span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'CALL_START'</span>
|
|
<span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-10">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-10">¶</a>
|
|
</div>
|
|
<p>The lexer has tagged the opening parenthesis of an indexing operation call.
|
|
Match it with its paired close.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> closeOpenIndexes: ->
|
|
<span class="function"><span class="title">condition</span></span> = (token, i) ->
|
|
token[<span class="number">0</span>] <span class="keyword">in</span> [<span class="string">']'</span>, <span class="string">'INDEX_END'</span>]
|
|
|
|
<span class="function"><span class="title">action</span></span> = (token, i) ->
|
|
token[<span class="number">0</span>] = <span class="string">'INDEX_END'</span>
|
|
|
|
<span class="property">@scanTokens</span> (token, i) ->
|
|
<span class="property">@detectEnd</span> i + <span class="number">1</span>, condition, action <span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'INDEX_START'</span>
|
|
<span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-11">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-11">¶</a>
|
|
</div>
|
|
<p>Match tags in token stream starting at i with pattern, skipping HERECOMMENTs
|
|
Pattern may consist of strings (equality), an array of strings (one of)
|
|
or null (wildcard)
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> matchTags: (i, pattern...) ->
|
|
fuzz = <span class="number">0</span>
|
|
<span class="keyword">for</span> j <span class="keyword">in</span> [<span class="number">0</span> ... pattern.length]
|
|
fuzz += <span class="number">2</span> <span class="keyword">while</span> <span class="property">@tag</span>(i + j + fuzz) <span class="keyword">is</span> <span class="string">'HERECOMMENT'</span>
|
|
<span class="keyword">continue</span> <span class="keyword">if</span> <span class="keyword">not</span> pattern[j]?
|
|
pattern[j] = [pattern[j]] <span class="keyword">if</span> <span class="keyword">typeof</span> pattern[j] <span class="keyword">is</span> <span class="string">'string'</span>
|
|
<span class="keyword">return</span> <span class="literal">no</span> <span class="keyword">if</span> <span class="property">@tag</span>(i + j + fuzz) <span class="keyword">not</span> <span class="keyword">in</span> pattern[j]
|
|
<span class="literal">yes</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-12">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-12">¶</a>
|
|
</div>
|
|
<p>yes iff standing in front of something looking like
|
|
@<x>: or <x>:, skipping over 'HERECOMMENT's
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> looksObjectish: (j) ->
|
|
<span class="property">@matchTags</span>(j, <span class="string">'@'</span>, <span class="literal">null</span>, <span class="string">':'</span>) <span class="keyword">or</span> <span class="property">@matchTags</span>(j, <span class="literal">null</span>, <span class="string">':'</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-13">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-13">¶</a>
|
|
</div>
|
|
<p>yes iff current line of tokens contain an element of tags on same
|
|
expression level. Stop searching at LINEBREAKS or explicit start of
|
|
containing balanced expression.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> findTagsBackwards: (i, tags) ->
|
|
backStack = []
|
|
<span class="keyword">while</span> i >= <span class="number">0</span> <span class="keyword">and</span> (backStack.length <span class="keyword">or</span>
|
|
<span class="property">@tag</span>(i) <span class="keyword">not</span> <span class="keyword">in</span> tags <span class="keyword">and</span>
|
|
(<span class="property">@tag</span>(i) <span class="keyword">not</span> <span class="keyword">in</span> EXPRESSION_START <span class="keyword">or</span> <span class="property">@tokens</span>[i].generated) <span class="keyword">and</span>
|
|
<span class="property">@tag</span>(i) <span class="keyword">not</span> <span class="keyword">in</span> LINEBREAKS)
|
|
backStack.push <span class="property">@tag</span>(i) <span class="keyword">if</span> <span class="property">@tag</span>(i) <span class="keyword">in</span> EXPRESSION_END
|
|
backStack.pop() <span class="keyword">if</span> <span class="property">@tag</span>(i) <span class="keyword">in</span> EXPRESSION_START <span class="keyword">and</span> backStack.length
|
|
i -= <span class="number">1</span>
|
|
<span class="property">@tag</span>(i) <span class="keyword">in</span> tags</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-14">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-14">¶</a>
|
|
</div>
|
|
<p>Look for signs of implicit calls and objects in the token stream and
|
|
add them.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> addImplicitBracesAndParens: -></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-15">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-15">¶</a>
|
|
</div>
|
|
<p>Track current balancing depth (both implicit and explicit) on stack.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> stack = []
|
|
|
|
<span class="property">@scanTokens</span> (token, i, tokens) ->
|
|
[tag] = token
|
|
[prevTag] = <span class="keyword">if</span> i > <span class="number">0</span> <span class="keyword">then</span> tokens[i - <span class="number">1</span>] <span class="keyword">else</span> []
|
|
[nextTag] = <span class="keyword">if</span> i < tokens.length - <span class="number">1</span> <span class="keyword">then</span> tokens[i + <span class="number">1</span>] <span class="keyword">else</span> []
|
|
<span class="function"><span class="title">stackTop</span></span> = -> stack[stack.length - <span class="number">1</span>]
|
|
startIdx = i</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-16">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-16">¶</a>
|
|
</div>
|
|
<p>Helper function, used for keeping track of the number of tokens consumed
|
|
and spliced, when returning for getting a new token.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="function"><span class="title">forward</span></span> = (n) -> i - startIdx + n</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-17">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-17">¶</a>
|
|
</div>
|
|
<p>Helper functions
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="function"><span class="title">inImplicit</span></span> = -> stackTop()?[<span class="number">2</span>]?.ours
|
|
<span class="function"><span class="title">inImplicitCall</span></span> = -> inImplicit() <span class="keyword">and</span> stackTop()?[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'('</span>
|
|
<span class="function"><span class="title">inImplicitObject</span></span> = -> inImplicit() <span class="keyword">and</span> stackTop()?[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'{'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-18">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-18">¶</a>
|
|
</div>
|
|
<p>Unclosed control statement inside implicit parens (like
|
|
class declaration or if-conditionals)
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="function"><span class="title">inImplicitControl</span></span> = -> inImplicit <span class="keyword">and</span> stackTop()?[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'CONTROL'</span>
|
|
|
|
<span class="function"><span class="title">startImplicitCall</span></span> = (j) ->
|
|
idx = j ? i
|
|
stack.push [<span class="string">'('</span>, idx, ours: <span class="literal">yes</span>]
|
|
tokens.splice idx, <span class="number">0</span>, generate <span class="string">'CALL_START'</span>, <span class="string">'('</span>
|
|
i += <span class="number">1</span> <span class="keyword">if</span> <span class="keyword">not</span> j?
|
|
|
|
<span class="function"><span class="title">endImplicitCall</span></span> = ->
|
|
stack.pop()
|
|
tokens.splice i, <span class="number">0</span>, generate <span class="string">'CALL_END'</span>, <span class="string">')'</span>
|
|
i += <span class="number">1</span>
|
|
|
|
<span class="function"><span class="title">startImplicitObject</span></span> = (j, startsLine = <span class="literal">yes</span>) ->
|
|
idx = j ? i
|
|
stack.push [<span class="string">'{'</span>, idx, sameLine: <span class="literal">yes</span>, startsLine: startsLine, ours: <span class="literal">yes</span>]
|
|
tokens.splice idx, <span class="number">0</span>, generate <span class="string">'{'</span>, generate(<span class="keyword">new</span> String(<span class="string">'{'</span>))
|
|
i += <span class="number">1</span> <span class="keyword">if</span> <span class="keyword">not</span> j?
|
|
|
|
<span class="function"><span class="title">endImplicitObject</span></span> = (j) ->
|
|
j = j ? i
|
|
stack.pop()
|
|
tokens.splice j, <span class="number">0</span>, generate <span class="string">'}'</span>, <span class="string">'}'</span>
|
|
i += <span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-19">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-19">¶</a>
|
|
</div>
|
|
<p>Don't end an implicit call on next indent if any of these are in an argument
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> inImplicitCall() <span class="keyword">and</span> tag <span class="keyword">in</span> [<span class="string">'IF'</span>, <span class="string">'TRY'</span>, <span class="string">'FINALLY'</span>, <span class="string">'CATCH'</span>,
|
|
<span class="string">'CLASS'</span>, <span class="string">'SWITCH'</span>]
|
|
stack.push [<span class="string">'CONTROL'</span>, i, ours: <span class="literal">true</span>]
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)
|
|
|
|
<span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'INDENT'</span> <span class="keyword">and</span> inImplicit()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-20">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-20">¶</a>
|
|
</div>
|
|
<p>An <code>INDENT</code> closes an implicit call unless
|
|
|
|
</p>
|
|
<ol>
|
|
<li>We have seen a <code>CONTROL</code> argument on the line.</li>
|
|
<li>The last token before the indent is part of the list below</li>
|
|
</ol>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> prevTag <span class="keyword">not</span> <span class="keyword">in</span> [<span class="string">'=>'</span>, <span class="string">'->'</span>, <span class="string">'['</span>, <span class="string">'('</span>, <span class="string">','</span>, <span class="string">'{'</span>, <span class="string">'TRY'</span>, <span class="string">'ELSE'</span>, <span class="string">'='</span>]
|
|
endImplicitCall() <span class="keyword">while</span> inImplicitCall()
|
|
stack.pop() <span class="keyword">if</span> inImplicitControl()
|
|
stack.push [tag, i]
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-21">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-21">¶</a>
|
|
</div>
|
|
<p>Straightforward start of explicit expression
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> tag <span class="keyword">in</span> EXPRESSION_START
|
|
stack.push [tag, i]
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-22">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-22">¶</a>
|
|
</div>
|
|
<p>Close all implicit expressions inside of explicitly closed expressions.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> tag <span class="keyword">in</span> EXPRESSION_END
|
|
<span class="keyword">while</span> inImplicit()
|
|
<span class="keyword">if</span> inImplicitCall()
|
|
endImplicitCall()
|
|
<span class="keyword">else</span> <span class="keyword">if</span> inImplicitObject()
|
|
endImplicitObject()
|
|
<span class="keyword">else</span>
|
|
stack.pop()
|
|
stack.pop()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-23">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-23">¶</a>
|
|
</div>
|
|
<p>Recognize standard implicit calls like
|
|
f a, f() b, f? c, h[0] d etc.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (tag <span class="keyword">in</span> IMPLICIT_FUNC <span class="keyword">and</span> token.spaced <span class="keyword">and</span> <span class="keyword">not</span> token.stringEnd <span class="keyword">or</span>
|
|
tag <span class="keyword">is</span> <span class="string">'?'</span> <span class="keyword">and</span> i > <span class="number">0</span> <span class="keyword">and</span> <span class="keyword">not</span> tokens[i - <span class="number">1</span>].spaced) <span class="keyword">and</span>
|
|
(nextTag <span class="keyword">in</span> IMPLICIT_CALL <span class="keyword">or</span>
|
|
nextTag <span class="keyword">in</span> IMPLICIT_UNSPACED_CALL <span class="keyword">and</span>
|
|
<span class="keyword">not</span> tokens[i + <span class="number">1</span>]?.spaced <span class="keyword">and</span> <span class="keyword">not</span> tokens[i + <span class="number">1</span>]?.newLine)
|
|
tag = token[<span class="number">0</span>] = <span class="string">'FUNC_EXIST'</span> <span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'?'</span>
|
|
startImplicitCall i + <span class="number">1</span>
|
|
<span class="keyword">return</span> forward(<span class="number">2</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-24">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-24">¶</a>
|
|
</div>
|
|
<p>Implicit call taking an implicit indented object as first argument.
|
|
|
|
</p>
|
|
<pre><code>f
|
|
a: b
|
|
c: d</code></pre>
|
|
<p>and
|
|
|
|
</p>
|
|
<pre><code>f
|
|
1
|
|
a: b
|
|
b: c</code></pre>
|
|
<p>Don't accept implicit calls of this type, when on the same line
|
|
as the control strucutures below as that may misinterpret constructs like:
|
|
|
|
</p>
|
|
<pre><code>if f
|
|
a: 1</code></pre>
|
|
<p>as
|
|
|
|
</p>
|
|
<pre><code>if f(a: 1)</code></pre>
|
|
<p>which is probably always unintended.
|
|
Furthermore don't allow this in literal arrays, as
|
|
that creates grammatical ambiguities.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> tag <span class="keyword">in</span> IMPLICIT_FUNC <span class="keyword">and</span> <span class="property">@matchTags</span>(i + <span class="number">1</span>, <span class="string">'INDENT'</span>, <span class="literal">null</span>, <span class="string">':'</span>) <span class="keyword">and</span>
|
|
<span class="keyword">not</span> <span class="property">@findTagsBackwards</span>(i, [<span class="string">'CLASS'</span>, <span class="string">'EXTENDS'</span>, <span class="string">'IF'</span>, <span class="string">'CATCH'</span>,
|
|
<span class="string">'SWITCH'</span>, <span class="string">'LEADING_WHEN'</span>, <span class="string">'FOR'</span>, <span class="string">'WHILE'</span>, <span class="string">'UNTIL'</span>])
|
|
startImplicitCall i + <span class="number">1</span>
|
|
stack.push [<span class="string">'INDENT'</span>, i + <span class="number">2</span>]
|
|
<span class="keyword">return</span> forward(<span class="number">3</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-25">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-25">¶</a>
|
|
</div>
|
|
<p>Implicit objects start here
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">':'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-26">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-26">¶</a>
|
|
</div>
|
|
<p>Go back to the (implicit) start of the object
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> <span class="property">@tag</span>(i - <span class="number">2</span>) <span class="keyword">is</span> <span class="string">'@'</span> <span class="keyword">then</span> s = i - <span class="number">2</span> <span class="keyword">else</span> s = i - <span class="number">1</span>
|
|
s -= <span class="number">2</span> <span class="keyword">while</span> <span class="property">@tag</span>(s - <span class="number">2</span>) <span class="keyword">is</span> <span class="string">'HERECOMMENT'</span>
|
|
|
|
startsLine = s <span class="keyword">is</span> <span class="number">0</span> <span class="keyword">or</span> <span class="property">@tag</span>(s - <span class="number">1</span>) <span class="keyword">in</span> LINEBREAKS <span class="keyword">or</span> tokens[s - <span class="number">1</span>].newLine</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-27">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-27">¶</a>
|
|
</div>
|
|
<p>Are we just continuing an already declared object?
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> stackTop()
|
|
[stackTag, stackIdx] = stackTop()
|
|
<span class="keyword">if</span> (stackTag <span class="keyword">is</span> <span class="string">'{'</span> <span class="keyword">or</span> stackTag <span class="keyword">is</span> <span class="string">'INDENT'</span> <span class="keyword">and</span> <span class="property">@tag</span>(stackIdx - <span class="number">1</span>) <span class="keyword">is</span> <span class="string">'{'</span>) <span class="keyword">and</span>
|
|
(startsLine <span class="keyword">or</span> <span class="property">@tag</span>(s - <span class="number">1</span>) <span class="keyword">is</span> <span class="string">','</span> <span class="keyword">or</span> <span class="property">@tag</span>(s - <span class="number">1</span>) <span class="keyword">is</span> <span class="string">'{'</span>)
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)
|
|
|
|
startImplicitObject(s, !!startsLine)
|
|
<span class="keyword">return</span> forward(<span class="number">2</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-28">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-28">¶</a>
|
|
</div>
|
|
<p>End implicit calls when chaining method calls
|
|
like e.g.:
|
|
|
|
</p>
|
|
<pre><code>f ->
|
|
a
|
|
.g b, ->
|
|
c
|
|
.h a</code></pre>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> prevTag <span class="keyword">is</span> <span class="string">'OUTDENT'</span> <span class="keyword">and</span> inImplicitCall() <span class="keyword">and</span> tag <span class="keyword">in</span> [<span class="string">'.'</span>, <span class="string">'?.'</span>, <span class="string">'::'</span>, <span class="string">'?::'</span>]
|
|
endImplicitCall()
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)
|
|
|
|
stackTop()[<span class="number">2</span>].sameLine = <span class="literal">no</span> <span class="keyword">if</span> inImplicitObject() <span class="keyword">and</span> tag <span class="keyword">in</span> LINEBREAKS
|
|
|
|
<span class="keyword">if</span> tag <span class="keyword">in</span> IMPLICIT_END
|
|
<span class="keyword">while</span> inImplicit()
|
|
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-29">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-29">¶</a>
|
|
</div>
|
|
<p>Close implicit calls when reached end of argument list
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> inImplicitCall() <span class="keyword">and</span> prevTag <span class="keyword">isnt</span> <span class="string">','</span>
|
|
endImplicitCall()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-30">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-30">¶</a>
|
|
</div>
|
|
<p>Close implicit objects such as:
|
|
return a: 1, b: 2 unless true
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">else</span> <span class="keyword">if</span> inImplicitObject() <span class="keyword">and</span> sameLine <span class="keyword">and</span> <span class="keyword">not</span> startsLine
|
|
endImplicitObject()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-31">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-31">¶</a>
|
|
</div>
|
|
<p>Close implicit objects when at end of line, line didn't end with a comma
|
|
and the implicit object didn't start the line or the next line doesn't look like
|
|
the continuation of an object.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">else</span> <span class="keyword">if</span> inImplicitObject() <span class="keyword">and</span> tag <span class="keyword">is</span> <span class="string">'TERMINATOR'</span> <span class="keyword">and</span> prevTag <span class="keyword">isnt</span> <span class="string">','</span> <span class="keyword">and</span>
|
|
<span class="keyword">not</span> (startsLine <span class="keyword">and</span> <span class="property">@looksObjectish</span>(i + <span class="number">1</span>))
|
|
endImplicitObject()
|
|
<span class="keyword">else</span>
|
|
<span class="keyword">break</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-32">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-32">¶</a>
|
|
</div>
|
|
<p>Close implicit object if comma is the last character
|
|
and what comes after doesn't look like it belongs.
|
|
This is used for trailing commas and calls, like:
|
|
|
|
</p>
|
|
<pre><code>x =
|
|
a: b,
|
|
c: d,
|
|
e = 2</code></pre>
|
|
<p>and
|
|
|
|
</p>
|
|
<pre><code>f a, b: c, d: e, f, g: h: i, j</code></pre>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">','</span> <span class="keyword">and</span> <span class="keyword">not</span> <span class="property">@looksObjectish</span>(i + <span class="number">1</span>) <span class="keyword">and</span> inImplicitObject() <span class="keyword">and</span>
|
|
(nextTag <span class="keyword">isnt</span> <span class="string">'TERMINATOR'</span> <span class="keyword">or</span> <span class="keyword">not</span> <span class="property">@looksObjectish</span>(i + <span class="number">2</span>))</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-33">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-33">¶</a>
|
|
</div>
|
|
<p>When nextTag is OUTDENT the comma is insignificant and
|
|
should just be ignored so embed it in the implicit object.
|
|
|
|
</p>
|
|
<p>When it isn't the comma go on to play a role in a call or
|
|
array further up the stack, so give it a chance.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
offset = <span class="keyword">if</span> nextTag <span class="keyword">is</span> <span class="string">'OUTDENT'</span> <span class="keyword">then</span> <span class="number">1</span> <span class="keyword">else</span> <span class="number">0</span>
|
|
<span class="keyword">while</span> inImplicitObject()
|
|
endImplicitObject i + offset
|
|
<span class="keyword">return</span> forward(<span class="number">1</span>)</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-34">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-34">¶</a>
|
|
</div>
|
|
<p>Add location data to all tokens generated by the rewriter.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> addLocationDataToGeneratedTokens: ->
|
|
<span class="property">@scanTokens</span> (token, i, tokens) ->
|
|
<span class="keyword">return</span> <span class="number">1</span> <span class="keyword">if</span> token[<span class="number">2</span>]
|
|
<span class="keyword">return</span> <span class="number">1</span> <span class="keyword">unless</span> token.generated <span class="keyword">or</span> token.explicit
|
|
<span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'{'</span> <span class="keyword">and</span> nextLocation=tokens[i + <span class="number">1</span>]?[<span class="number">2</span>]
|
|
{first_line: line, first_column: column} = nextLocation
|
|
<span class="keyword">else</span> <span class="keyword">if</span> prevLocation = tokens[i - <span class="number">1</span>]?[<span class="number">2</span>]
|
|
{last_line: line, last_column: column} = prevLocation
|
|
<span class="keyword">else</span>
|
|
line = column = <span class="number">0</span>
|
|
token[<span class="number">2</span>] =
|
|
first_line: line
|
|
first_column: column
|
|
last_line: line
|
|
last_column: column
|
|
<span class="keyword">return</span> <span class="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>Because our grammar is LALR(1), it can't handle some single-line
|
|
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
|
|
blocks, so it doesn't need to. ')' can close a single-line block,
|
|
but we need to make sure it's balanced.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> addImplicitIndentation: ->
|
|
starter = indent = outdent = <span class="literal">null</span>
|
|
|
|
<span class="function"><span class="title">condition</span></span> = (token, i) ->
|
|
token[<span class="number">1</span>] <span class="keyword">isnt</span> <span class="string">';'</span> <span class="keyword">and</span> token[<span class="number">0</span>] <span class="keyword">in</span> SINGLE_CLOSERS <span class="keyword">and</span>
|
|
<span class="keyword">not</span> (token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'ELSE'</span> <span class="keyword">and</span> starter <span class="keyword">isnt</span> <span class="string">'THEN'</span>) <span class="keyword">and</span>
|
|
<span class="keyword">not</span> (token[<span class="number">0</span>] <span class="keyword">in</span> [<span class="string">'CATCH'</span>, <span class="string">'FINALLY'</span>] <span class="keyword">and</span> starter <span class="keyword">in</span> [<span class="string">'->'</span>, <span class="string">'=>'</span>])
|
|
|
|
<span class="function"><span class="title">action</span></span> = (token, i) ->
|
|
<span class="property">@tokens</span>.splice (<span class="keyword">if</span> <span class="property">@tag</span>(i - <span class="number">1</span>) <span class="keyword">is</span> <span class="string">','</span> <span class="keyword">then</span> i - <span class="number">1</span> <span class="keyword">else</span> i), <span class="number">0</span>, outdent
|
|
|
|
<span class="property">@scanTokens</span> (token, i, tokens) ->
|
|
[tag] = token
|
|
<span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'TERMINATOR'</span> <span class="keyword">and</span> <span class="property">@tag</span>(i + <span class="number">1</span>) <span class="keyword">is</span> <span class="string">'THEN'</span>
|
|
tokens.splice i, <span class="number">1</span>
|
|
<span class="keyword">return</span> <span class="number">0</span>
|
|
<span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'ELSE'</span> <span class="keyword">and</span> <span class="property">@tag</span>(i - <span class="number">1</span>) <span class="keyword">isnt</span> <span class="string">'OUTDENT'</span>
|
|
tokens.splice i, <span class="number">0</span>, <span class="property">@indentation</span>()...
|
|
<span class="keyword">return</span> <span class="number">2</span>
|
|
<span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'CATCH'</span>
|
|
<span class="keyword">for</span> j <span class="keyword">in</span> [<span class="number">1.</span><span class="number">.2</span>] <span class="keyword">when</span> <span class="property">@tag</span>(i + j) <span class="keyword">in</span> [<span class="string">'OUTDENT'</span>, <span class="string">'TERMINATOR'</span>, <span class="string">'FINALLY'</span>]
|
|
tokens.splice i + j, <span class="number">0</span>, <span class="property">@indentation</span>()...
|
|
<span class="keyword">return</span> <span class="number">2</span> + j
|
|
<span class="keyword">if</span> tag <span class="keyword">in</span> SINGLE_LINERS <span class="keyword">and</span> <span class="property">@tag</span>(i + <span class="number">1</span>) <span class="keyword">isnt</span> <span class="string">'INDENT'</span> <span class="keyword">and</span>
|
|
<span class="keyword">not</span> (tag <span class="keyword">is</span> <span class="string">'ELSE'</span> <span class="keyword">and</span> <span class="property">@tag</span>(i + <span class="number">1</span>) <span class="keyword">is</span> <span class="string">'IF'</span>)
|
|
starter = tag
|
|
[indent, outdent] = <span class="property">@indentation</span> <span class="literal">yes</span>
|
|
indent.fromThen = <span class="literal">true</span> <span class="keyword">if</span> starter <span class="keyword">is</span> <span class="string">'THEN'</span>
|
|
tokens.splice i + <span class="number">1</span>, <span class="number">0</span>, indent
|
|
<span class="property">@detectEnd</span> i + <span class="number">2</span>, condition, action
|
|
tokens.splice i, <span class="number">1</span> <span class="keyword">if</span> tag <span class="keyword">is</span> <span class="string">'THEN'</span>
|
|
<span class="keyword">return</span> <span class="number">1</span>
|
|
<span class="keyword">return</span> <span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-36">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-36">¶</a>
|
|
</div>
|
|
<p>Tag postfix conditionals as such, so that we can parse them with a
|
|
different precedence.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> tagPostfixConditionals: ->
|
|
|
|
original = <span class="literal">null</span>
|
|
|
|
<span class="function"><span class="title">condition</span></span> = (token, i) ->
|
|
[tag] = token
|
|
[prevTag] = <span class="property">@tokens</span>[i - <span class="number">1</span>]
|
|
tag <span class="keyword">is</span> <span class="string">'TERMINATOR'</span> <span class="keyword">or</span> (tag <span class="keyword">is</span> <span class="string">'INDENT'</span> <span class="keyword">and</span> prevTag <span class="keyword">not</span> <span class="keyword">in</span> SINGLE_LINERS)
|
|
|
|
<span class="function"><span class="title">action</span></span> = (token, i) ->
|
|
<span class="keyword">if</span> token[<span class="number">0</span>] <span class="keyword">isnt</span> <span class="string">'INDENT'</span> <span class="keyword">or</span> (token.generated <span class="keyword">and</span> <span class="keyword">not</span> token.fromThen)
|
|
original[<span class="number">0</span>] = <span class="string">'POST_'</span> + original[<span class="number">0</span>]
|
|
|
|
<span class="property">@scanTokens</span> (token, i) ->
|
|
<span class="keyword">return</span> <span class="number">1</span> <span class="keyword">unless</span> token[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">'IF'</span>
|
|
original = token
|
|
<span class="property">@detectEnd</span> i + <span class="number">1</span>, condition, action
|
|
<span class="keyword">return</span> <span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-37">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-37">¶</a>
|
|
</div>
|
|
<p>Generate the indentation tokens, based on another token on the same line.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> indentation: (implicit = <span class="literal">no</span>) ->
|
|
indent = [<span class="string">'INDENT'</span>, <span class="number">2</span>]
|
|
outdent = [<span class="string">'OUTDENT'</span>, <span class="number">2</span>]
|
|
indent.generated = outdent.generated = <span class="literal">yes</span> <span class="keyword">if</span> implicit
|
|
indent.explicit = outdent.explicit = <span class="literal">yes</span> <span class="keyword">if</span> <span class="keyword">not</span> implicit
|
|
[indent, outdent]
|
|
|
|
generate: generate</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-38">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-38">¶</a>
|
|
</div>
|
|
<p>Look up a tag by token index.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> tag: (i) -> <span class="property">@tokens</span>[i]?[<span class="number">0</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-39">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-39">¶</a>
|
|
</div>
|
|
<h2>Constants</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-40">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-40">¶</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-41">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-41">¶</a>
|
|
</div>
|
|
<p>List of the token pairs that must be balanced.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>BALANCED_PAIRS = [
|
|
[<span class="string">'('</span>, <span class="string">')'</span>]
|
|
[<span class="string">'['</span>, <span class="string">']'</span>]
|
|
[<span class="string">'{'</span>, <span class="string">'}'</span>]
|
|
[<span class="string">'INDENT'</span>, <span class="string">'OUTDENT'</span>],
|
|
[<span class="string">'CALL_START'</span>, <span class="string">'CALL_END'</span>]
|
|
[<span class="string">'PARAM_START'</span>, <span class="string">'PARAM_END'</span>]
|
|
[<span class="string">'INDEX_START'</span>, <span class="string">'INDEX_END'</span>]
|
|
]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-42">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-42">¶</a>
|
|
</div>
|
|
<p>The inverse mappings of <code>BALANCED_PAIRS</code> we're trying to fix up, so we can
|
|
look things up from either end.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>exports.INVERSES = INVERSES = {}</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-43">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-43">¶</a>
|
|
</div>
|
|
<p>The tokens that signal the start/end of a balanced pair.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>EXPRESSION_START = []
|
|
EXPRESSION_END = []
|
|
|
|
<span class="keyword">for</span> [left, rite] <span class="keyword">in</span> BALANCED_PAIRS
|
|
EXPRESSION_START.push INVERSES[rite] = left
|
|
EXPRESSION_END .push INVERSES[left] = rite</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-44">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-44">¶</a>
|
|
</div>
|
|
<p>Tokens that indicate the close of a clause of an expression.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>EXPRESSION_CLOSE = [<span class="string">'CATCH'</span>, <span class="string">'WHEN'</span>, <span class="string">'ELSE'</span>, <span class="string">'FINALLY'</span>].concat EXPRESSION_END</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-45">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-45">¶</a>
|
|
</div>
|
|
<p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>IMPLICIT_FUNC = [<span class="string">'IDENTIFIER'</span>, <span class="string">'SUPER'</span>, <span class="string">')'</span>, <span class="string">'CALL_END'</span>, <span class="string">']'</span>, <span class="string">'INDEX_END'</span>, <span class="string">'@'</span>, <span class="string">'THIS'</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-46">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-46">¶</a>
|
|
</div>
|
|
<p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>IMPLICIT_CALL = [
|
|
<span class="string">'IDENTIFIER'</span>, <span class="string">'NUMBER'</span>, <span class="string">'STRING'</span>, <span class="string">'JS'</span>, <span class="string">'REGEX'</span>, <span class="string">'NEW'</span>, <span class="string">'PARAM_START'</span>, <span class="string">'CLASS'</span>
|
|
<span class="string">'IF'</span>, <span class="string">'TRY'</span>, <span class="string">'SWITCH'</span>, <span class="string">'THIS'</span>, <span class="string">'BOOL'</span>, <span class="string">'NULL'</span>, <span class="string">'UNDEFINED'</span>, <span class="string">'UNARY'</span>, <span class="string">'SUPER'</span>
|
|
<span class="string">'THROW'</span>, <span class="string">'@'</span>, <span class="string">'->'</span>, <span class="string">'=>'</span>, <span class="string">'['</span>, <span class="string">'('</span>, <span class="string">'{'</span>, <span class="string">'--'</span>, <span class="string">'++'</span>
|
|
]
|
|
|
|
IMPLICIT_UNSPACED_CALL = [<span class="string">'+'</span>, <span class="string">'-'</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-47">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-47">¶</a>
|
|
</div>
|
|
<p>Tokens that always mark the end of an implicit call for single-liners.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>IMPLICIT_END = [<span class="string">'POST_IF'</span>, <span class="string">'FOR'</span>, <span class="string">'WHILE'</span>, <span class="string">'UNTIL'</span>, <span class="string">'WHEN'</span>, <span class="string">'BY'</span>,
|
|
<span class="string">'LOOP'</span>, <span class="string">'TERMINATOR'</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-48">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-48">¶</a>
|
|
</div>
|
|
<p>Single-line flavors of block expressions that have unclosed endings.
|
|
The grammar can't disambiguate them, so we insert the implicit indentation.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>SINGLE_LINERS = [<span class="string">'ELSE'</span>, <span class="string">'->'</span>, <span class="string">'=>'</span>, <span class="string">'TRY'</span>, <span class="string">'FINALLY'</span>, <span class="string">'THEN'</span>]
|
|
SINGLE_CLOSERS = [<span class="string">'TERMINATOR'</span>, <span class="string">'CATCH'</span>, <span class="string">'FINALLY'</span>, <span class="string">'ELSE'</span>, <span class="string">'OUTDENT'</span>, <span class="string">'LEADING_WHEN'</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-49">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-49">¶</a>
|
|
</div>
|
|
<p>Tokens that end a line.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>LINEBREAKS = [<span class="string">'TERMINATOR'</span>, <span class="string">'INDENT'</span>, <span class="string">'OUTDENT'</span>]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|