mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
431 lines
16 KiB
HTML
431 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html>
|
|
<head>
|
|
<title>scope.litcoffee</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>scope.litcoffee</h1>
|
|
</div>
|
|
</li>
|
|
|
|
|
|
|
|
<li id="section-1">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-1">¶</a>
|
|
</div>
|
|
<p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
|
|
generate code, you create a tree of scopes in the same shape as the nested
|
|
function bodies. Each scope knows about the variables declared within it,
|
|
and has a reference to its parent enclosing scope. In this way, we know which
|
|
variables are new and need to be declared with <code>var</code>, and which are shared
|
|
with external scopes.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-2">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-2">¶</a>
|
|
</div>
|
|
<p>Import the helpers we plan to use.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
{extend, last} = require <span class="string">'./helpers'</span>
|
|
|
|
exports.Scope = <span class="class"><span class="keyword">class</span> <span class="title">Scope</span></span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-3">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-3">¶</a>
|
|
</div>
|
|
<p>The <code>root</code> is the top-level <strong>Scope</strong> object for a given file.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
<span class="property">@root</span>: <span class="literal">null</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-4">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-4">¶</a>
|
|
</div>
|
|
<p>Initialize a scope with its parent, for lookups up the chain,
|
|
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
|
where it should declare its variables, and a reference to the function that
|
|
it belongs to.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
constructor: (<span class="property">@parent</span>, <span class="property">@expressions</span>, <span class="property">@method</span>) ->
|
|
<span class="property">@variables</span> = [{name: <span class="string">'arguments'</span>, type: <span class="string">'arguments'</span>}]
|
|
<span class="property">@positions</span> = {}
|
|
Scope.root = <span class="keyword">this</span> <span class="keyword">unless</span> <span class="property">@parent</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-5">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-5">¶</a>
|
|
</div>
|
|
<p>Adds a new variable or overrides an existing one.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
add: (name, type, immediate) ->
|
|
<span class="keyword">return</span> <span class="property">@parent</span>.add name, type, immediate <span class="keyword">if</span> <span class="property">@shared</span> <span class="keyword">and</span> <span class="keyword">not</span> immediate
|
|
<span class="keyword">if</span> Object::hasOwnProperty.call <span class="property">@positions</span>, name
|
|
<span class="property">@variables</span>[<span class="property">@positions</span>[name]].type = type
|
|
<span class="keyword">else</span>
|
|
<span class="property">@positions</span>[name] = <span class="property">@variables</span>.push({name, type}) - <span class="number">1</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-6">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-6">¶</a>
|
|
</div>
|
|
<p>When <code>super</code> is called, we need to find the name of the current method we're
|
|
in, so that we know how to invoke the same method of the parent class. This
|
|
can get complicated if super is being called from an inner function.
|
|
<code>namedMethod</code> will walk up the scope tree until it either finds the first
|
|
function object that has a name filled in, or bottoms out.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
namedMethod: ->
|
|
<span class="keyword">return</span> <span class="property">@method</span> <span class="keyword">if</span> <span class="property">@method</span>?.name <span class="keyword">or</span> !<span class="property">@parent</span>
|
|
<span class="property">@parent</span>.namedMethod()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-7">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-7">¶</a>
|
|
</div>
|
|
<p>Look up a variable name in lexical scope, and declare it if it does not
|
|
already exist.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
find: (name) ->
|
|
<span class="keyword">return</span> <span class="literal">yes</span> <span class="keyword">if</span> <span class="property">@check</span> name
|
|
<span class="property">@add</span> name, <span class="string">'var'</span>
|
|
<span class="literal">no</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-8">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-8">¶</a>
|
|
</div>
|
|
<p>Reserve a variable name as originating from a function parameter for this
|
|
scope. No <code>var</code> required for internal references.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
parameter: (name) ->
|
|
<span class="keyword">return</span> <span class="keyword">if</span> <span class="property">@shared</span> <span class="keyword">and</span> <span class="property">@parent</span>.check name, <span class="literal">yes</span>
|
|
<span class="property">@add</span> name, <span class="string">'param'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-9">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-9">¶</a>
|
|
</div>
|
|
<p>Just check to see if a variable has already been declared, without reserving,
|
|
walks up to the root scope.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
check: (name) ->
|
|
!!(<span class="property">@type</span>(name) <span class="keyword">or</span> <span class="property">@parent</span>?.check(name))</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-10">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-10">¶</a>
|
|
</div>
|
|
<p>Generate a temporary variable name at the given index.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
temporary: (name, index) ->
|
|
<span class="keyword">if</span> name.length > <span class="number">1</span>
|
|
<span class="string">'_'</span> + name + <span class="keyword">if</span> index > <span class="number">1</span> <span class="keyword">then</span> index - <span class="number">1</span> <span class="keyword">else</span> <span class="string">''</span>
|
|
<span class="keyword">else</span>
|
|
<span class="string">'_'</span> + (index + parseInt name, <span class="number">36</span>).toString(<span class="number">36</span>).replace <span class="regexp">/\d/g</span>, <span class="string">'a'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-11">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-11">¶</a>
|
|
</div>
|
|
<p>Gets the type of a variable.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
type: (name) ->
|
|
<span class="keyword">return</span> v.type <span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.name <span class="keyword">is</span> name
|
|
<span class="literal">null</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-12">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-12">¶</a>
|
|
</div>
|
|
<p>If we need to store an intermediate result, find an available name for a
|
|
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
freeVariable: (name, reserve=<span class="literal">true</span>) ->
|
|
index = <span class="number">0</span>
|
|
index++ <span class="keyword">while</span> <span class="property">@check</span>((temp = <span class="property">@temporary</span> name, index))
|
|
<span class="property">@add</span> temp, <span class="string">'var'</span>, <span class="literal">yes</span> <span class="keyword">if</span> reserve
|
|
temp</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-13">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-13">¶</a>
|
|
</div>
|
|
<p>Ensure that an assignment is made at the top of this scope
|
|
(or at the top-level scope, if requested).
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
assign: (name, value) ->
|
|
<span class="property">@add</span> name, {value, assigned: <span class="literal">yes</span>}, <span class="literal">yes</span>
|
|
<span class="property">@hasAssignments</span> = <span class="literal">yes</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-14">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-14">¶</a>
|
|
</div>
|
|
<p>Does this scope have any declared variables?
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
hasDeclarations: ->
|
|
!!<span class="property">@declaredVariables</span>().length</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-15">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-15">¶</a>
|
|
</div>
|
|
<p>Return the list of variables first declared in this scope.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
declaredVariables: ->
|
|
realVars = []
|
|
tempVars = []
|
|
<span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.type <span class="keyword">is</span> <span class="string">'var'</span>
|
|
(<span class="keyword">if</span> v.name.charAt(<span class="number">0</span>) <span class="keyword">is</span> <span class="string">'_'</span> <span class="keyword">then</span> tempVars <span class="keyword">else</span> realVars).push v.name
|
|
realVars.sort().concat tempVars.sort()</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-16">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-16">¶</a>
|
|
</div>
|
|
<p>Return the list of assignments that are supposed to be made at the top
|
|
of this scope.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>
|
|
assignedVariables: ->
|
|
<span class="string">"<span class="subst">#{v.name}</span> = <span class="subst">#{v.type.value}</span>"</span> <span class="keyword">for</span> v <span class="keyword">in</span> <span class="property">@variables</span> <span class="keyword">when</span> v.type.assigned</pre></div></div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|