mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
cbc695b831
* Give the notes about `super` and `this` their own section in the docs * 2.0.2 changelog * 2.0.2 release output * Rewrite
400 lines
16 KiB
HTML
400 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_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="coffeescript.html">
|
||
coffeescript.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>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>
|
||
|
||
<div class="content"><div class='highlight'><pre>exports.Scope = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Scope</span></span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-2">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-2">¶</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, a reference to the function that
|
||
it belongs to, and a list of variables referenced in the source code
|
||
and therefore should be avoided when generating variables. Also track comments
|
||
that should be output as part of variable declarations.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> constructor: <span class="hljs-function"><span class="hljs-params">(@parent, @expressions, @method, @referencedVars)</span> -></span>
|
||
@variables = [{name: <span class="hljs-string">'arguments'</span>, type: <span class="hljs-string">'arguments'</span>}]
|
||
@comments = {}
|
||
@positions = {}
|
||
@utilities = {} <span class="hljs-keyword">unless</span> @parent</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> @root = @parent?.root ? <span class="hljs-keyword">this</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-4">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-4">¶</a>
|
||
</div>
|
||
<p>Adds a new variable or overrides an existing one.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> add: <span class="hljs-function"><span class="hljs-params">(name, type, immediate)</span> -></span>
|
||
<span class="hljs-keyword">return</span> @parent.add name, type, immediate <span class="hljs-keyword">if</span> @shared <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> immediate
|
||
<span class="hljs-keyword">if</span> Object::hasOwnProperty.call @positions, name
|
||
@variables[@positions[name]].type = type
|
||
<span class="hljs-keyword">else</span>
|
||
@positions[name] = @variables.push({name, type}) - <span class="hljs-number">1</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-5">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-5">¶</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="hljs-function">-></span>
|
||
<span class="hljs-keyword">return</span> @method <span class="hljs-keyword">if</span> @method?.name <span class="hljs-keyword">or</span> !@parent
|
||
@parent.namedMethod()</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-6">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-6">¶</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: <span class="hljs-function"><span class="hljs-params">(name, type = <span class="hljs-string">'var'</span>)</span> -></span>
|
||
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> @check name
|
||
@add name, type
|
||
<span class="hljs-literal">no</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-7">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-7">¶</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: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span>
|
||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> @shared <span class="hljs-keyword">and</span> @parent.check name, <span class="hljs-literal">yes</span>
|
||
@add name, <span class="hljs-string">'param'</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-8">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-8">¶</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: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span>
|
||
!!(@type(name) <span class="hljs-keyword">or</span> @parent?.check(name))</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-9">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-9">¶</a>
|
||
</div>
|
||
<p>Generate a temporary variable name at the given index.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> temporary: <span class="hljs-function"><span class="hljs-params">(name, index, single=<span class="hljs-literal">false</span>)</span> -></span>
|
||
<span class="hljs-keyword">if</span> single
|
||
startCode = name.charCodeAt(<span class="hljs-number">0</span>)
|
||
endCode = <span class="hljs-string">'z'</span>.charCodeAt(<span class="hljs-number">0</span>)
|
||
diff = endCode - startCode
|
||
newCode = startCode + index % (diff + <span class="hljs-number">1</span>)
|
||
letter = String.fromCharCode(newCode)
|
||
num = index <span class="hljs-regexp">//</span> (diff + <span class="hljs-number">1</span>)
|
||
<span class="hljs-string">"<span class="hljs-subst">#{letter}</span><span class="hljs-subst">#{num <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span>"</span>
|
||
<span class="hljs-keyword">else</span>
|
||
<span class="hljs-string">"<span class="hljs-subst">#{name}</span><span class="hljs-subst">#{index <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>}</span>"</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-10">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-10">¶</a>
|
||
</div>
|
||
<p>Gets the type of a variable.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> type: <span class="hljs-function"><span class="hljs-params">(name)</span> -></span>
|
||
<span class="hljs-keyword">return</span> v.type <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> @variables <span class="hljs-keyword">when</span> v.name <span class="hljs-keyword">is</span> name
|
||
<span class="hljs-literal">null</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-11">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-11">¶</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: <span class="hljs-function"><span class="hljs-params">(name, options={})</span> -></span>
|
||
index = <span class="hljs-number">0</span>
|
||
<span class="hljs-keyword">loop</span>
|
||
temp = @temporary name, index, options.single
|
||
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> @check(temp) <span class="hljs-keyword">or</span> temp <span class="hljs-keyword">in</span> @root.referencedVars
|
||
index++
|
||
@add temp, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> options.reserve ? <span class="hljs-literal">true</span>
|
||
temp</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-12">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-12">¶</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: <span class="hljs-function"><span class="hljs-params">(name, value)</span> -></span>
|
||
@add name, {value, assigned: <span class="hljs-literal">yes</span>}, <span class="hljs-literal">yes</span>
|
||
@hasAssignments = <span class="hljs-literal">yes</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-13">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-13">¶</a>
|
||
</div>
|
||
<p>Does this scope have any declared variables?</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> hasDeclarations: <span class="hljs-function">-></span>
|
||
!!@declaredVariables().length</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-14">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-14">¶</a>
|
||
</div>
|
||
<p>Return the list of variables first declared in this scope.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> declaredVariables: <span class="hljs-function">-></span>
|
||
(v.name <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> @variables <span class="hljs-keyword">when</span> v.type <span class="hljs-keyword">is</span> <span class="hljs-string">'var'</span>).sort()</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 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="hljs-function">-></span>
|
||
<span class="hljs-string">"<span class="hljs-subst">#{v.name}</span> = <span class="hljs-subst">#{v.type.value}</span>"</span> <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> @variables <span class="hljs-keyword">when</span> v.type.assigned</pre></div></div>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
</html>
|