5508 lines
279 KiB
HTML
5508 lines
279 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<title>acorn.js</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 class="sections">
|
||
|
||
<li id="title">
|
||
<div class="annotation">
|
||
<h1>acorn.js</h1>
|
||
</div>
|
||
</li>
|
||
|
||
|
||
|
||
<li id="section-1">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-1">¶</a>
|
||
</div>
|
||
<p>Acorn is a tiny, fast JavaScript parser written in JavaScript.</p>
|
||
<p>Acorn was written by Marijn Haverbeke and various contributors and
|
||
released under an MIT license. The Unicode regexps (for identifiers
|
||
and whitespace) were taken from <a href="http://esprima.org">Esprima</a> by
|
||
Ariya Hidayat.</p>
|
||
<p>Git repositories for Acorn are available at</p>
|
||
<pre><code>http:<span class="hljs-comment">//marijnhaverbeke.nl/git/acorn</span>
|
||
https:<span class="hljs-comment">//github.com/marijnh/acorn.git</span>
|
||
</code></pre><p>Please use the <a href="https://github.com/marijnh/acorn/issues">github bug tracker</a> to report issues.</p>
|
||
<p>This file defines the main parser interface. The library also comes
|
||
with a <a href="acorn_loose.js">error-tolerant parser</a> and an
|
||
<a href="util/walk.js">abstract syntax tree walker</a>, defined in other files.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(root, mod)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> exports == <span class="hljs-string">"object"</span> && <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span> == <span class="hljs-string">"object"</span>) <span class="hljs-keyword">return</span> mod(exports); <span class="hljs-comment">// CommonJS</span>
|
||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> define == <span class="hljs-string">"function"</span> && define.amd) <span class="hljs-keyword">return</span> define([<span class="hljs-string">"exports"</span>], mod); <span class="hljs-comment">// AMD</span>
|
||
mod(root.acorn || (root.acorn = {})); <span class="hljs-comment">// Plain browser env</span>
|
||
})(<span class="hljs-keyword">this</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(exports)</span> </span>{
|
||
<span class="hljs-pi"> "use strict"</span>;
|
||
|
||
exports.version = <span class="hljs-string">"0.7.1"</span>;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-2">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-2">¶</a>
|
||
</div>
|
||
<p>The main exported interface (under <code>self.acorn</code> when in the
|
||
browser) is a <code>parse</code> function that takes a code string and
|
||
returns an abstract syntax tree as specified by <a href="https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API">Mozilla parser
|
||
API</a>, with the caveat that inline XML is not recognized.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> options, input, inputLen, sourceFile;
|
||
|
||
exports.parse = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(inpt, opts)</span> </span>{
|
||
input = <span class="hljs-built_in">String</span>(inpt); inputLen = input.length;
|
||
setOptions(opts);
|
||
initTokenState();
|
||
<span class="hljs-keyword">return</span> parseTopLevel(options.program);
|
||
};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-3">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-3">¶</a>
|
||
</div>
|
||
<p>A second optional argument can be given to further configure
|
||
the parser process. These options are recognized:</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> defaultOptions = exports.defaultOptions = {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-4">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-4">¶</a>
|
||
</div>
|
||
<p><code>ecmaVersion</code> indicates the ECMAScript version to parse. Must
|
||
be either 3, or 5, or 6. This influences support for strict
|
||
mode, the set of reserved words, support for getters and
|
||
setters and other features.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> ecmaVersion: <span class="hljs-number">5</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-5">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-5">¶</a>
|
||
</div>
|
||
<p>Turn on <code>strictSemicolons</code> to prevent the parser from doing
|
||
automatic semicolon insertion.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> strictSemicolons: <span class="hljs-literal">false</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>allowTrailingCommas</code> is false, the parser will not allow
|
||
trailing commas in array and object literals.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> allowTrailingCommas: <span class="hljs-literal">true</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-7">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-7">¶</a>
|
||
</div>
|
||
<p>By default, reserved words are not enforced. Enable
|
||
<code>forbidReserved</code> to enforce them. When this option has the
|
||
value “everywhere”, reserved words and keywords can also not be
|
||
used as property names.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> forbidReserved: <span class="hljs-literal">false</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-8">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-8">¶</a>
|
||
</div>
|
||
<p>When enabled, a return at the top level is not considered an
|
||
error.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> allowReturnOutsideFunction: <span class="hljs-literal">false</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-9">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-9">¶</a>
|
||
</div>
|
||
<p>When <code>locations</code> is on, <code>loc</code> properties holding objects with
|
||
<code>start</code> and <code>end</code> properties in <code>{line, column}</code> form (with
|
||
line being 1-based and column 0-based) will be attached to the
|
||
nodes.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> locations: <span class="hljs-literal">false</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-10">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-10">¶</a>
|
||
</div>
|
||
<p>A function can be passed as <code>onToken</code> option, which will
|
||
cause Acorn to call that function with object in the same
|
||
format as tokenize() returns. Note that you are not
|
||
allowed to call the parser from the callback—that will
|
||
corrupt its internal state.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> onToken: <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>A function can be passed as <code>onComment</code> option, which will
|
||
cause Acorn to call that function with <code>(block, text, start,
|
||
end)</code> parameters whenever a comment is skipped. <code>block</code> is a
|
||
boolean indicating whether this is a block (<code>/* */</code>) comment,
|
||
<code>text</code> is the content of the comment, and <code>start</code> and <code>end</code> are
|
||
character offsets that denote the start and end of the comment.
|
||
When the <code>locations</code> option is on, two more parameters are
|
||
passed, the full <code>{line, column}</code> locations of the start and
|
||
end of the comments. Note that you are not allowed to call the
|
||
parser from the callback—that will corrupt its internal state.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> onComment: <span class="hljs-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>Nodes have their start and end characters offsets recorded in
|
||
<code>start</code> and <code>end</code> properties (directly on the node, rather than
|
||
the <code>loc</code> object, which holds line/column data. To also add a
|
||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=745678">semi-standardized</a> <code>range</code> property holding a <code>[start,
|
||
end]</code> array with the same numbers, set the <code>ranges</code> option to
|
||
<code>true</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> ranges: <span class="hljs-literal">false</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-13">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-13">¶</a>
|
||
</div>
|
||
<p>It is possible to parse multiple files into a single AST by
|
||
passing the tree produced by parsing the first file as
|
||
<code>program</code> option in subsequent parses. This will add the
|
||
toplevel forms of the parsed file to the <code>Program</code> (top) node
|
||
of an existing parse tree.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> program: <span class="hljs-literal">null</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-14">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-14">¶</a>
|
||
</div>
|
||
<p>When <code>locations</code> is on, you can pass this to record the source
|
||
file in every node’s <code>loc</code> object.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> sourceFile: <span class="hljs-literal">null</span>,</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-15">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-15">¶</a>
|
||
</div>
|
||
<p>This value, if given, is stored in every node, whether
|
||
<code>locations</code> is on or off.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> directSourceFile: <span class="hljs-literal">null</span>
|
||
};
|
||
|
||
<span class="hljs-keyword">var</span> isArray = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(obj)</span> </span>{
|
||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.prototype.toString.call(obj) === <span class="hljs-string">"[object Array]"</span>;
|
||
};
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setOptions</span><span class="hljs-params">(opts)</span> </span>{
|
||
options = opts || {};
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> opt <span class="hljs-keyword">in</span> defaultOptions) <span class="hljs-keyword">if</span> (!has(options, opt))
|
||
options[opt] = defaultOptions[opt];
|
||
sourceFile = options.sourceFile || <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">if</span> (isArray(options.onToken)) {
|
||
<span class="hljs-keyword">var</span> tokens = options.onToken;
|
||
options.onToken = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(token)</span> </span>{
|
||
tokens.push(token);
|
||
};
|
||
}
|
||
<span class="hljs-keyword">if</span> (isArray(options.onComment)) {
|
||
<span class="hljs-keyword">var</span> comments = options.onComment;
|
||
options.onComment = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(block, text, start, end, startLoc, endLoc)</span> </span>{
|
||
<span class="hljs-keyword">var</span> comment = {
|
||
type: block ? <span class="hljs-string">'Block'</span> : <span class="hljs-string">'Line'</span>,
|
||
value: text,
|
||
start: start,
|
||
end: end
|
||
};
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
comment.loc = <span class="hljs-keyword">new</span> SourceLocation();
|
||
comment.loc.start = startLoc;
|
||
comment.loc.end = endLoc;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.ranges)
|
||
comment.range = [start, end];
|
||
comments.push(comment);
|
||
};
|
||
}
|
||
isKeyword = options.ecmaVersion >= <span class="hljs-number">6</span> ? isEcma6Keyword : isEcma5AndLessKeyword;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-16">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-16">¶</a>
|
||
</div>
|
||
<p>The <code>getLineInfo</code> function is mostly useful when the
|
||
<code>locations</code> option is off (for performance reasons) and you
|
||
want to find the line/column position for a given character
|
||
offset. <code>input</code> should be the code string that the offset refers
|
||
into.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> getLineInfo = exports.getLineInfo = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(input, offset)</span> </span>{
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> line = <span class="hljs-number">1</span>, cur = <span class="hljs-number">0</span>;;) {
|
||
lineBreak.lastIndex = cur;
|
||
<span class="hljs-keyword">var</span> match = lineBreak.exec(input);
|
||
<span class="hljs-keyword">if</span> (match && match.index < offset) {
|
||
++line;
|
||
cur = match.index + match[<span class="hljs-number">0</span>].length;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">break</span>;
|
||
}
|
||
<span class="hljs-keyword">return</span> {line: line, column: offset - cur};
|
||
};
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Token</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">this</span>.type = tokType;
|
||
<span class="hljs-keyword">this</span>.value = tokVal;
|
||
<span class="hljs-keyword">this</span>.start = tokStart;
|
||
<span class="hljs-keyword">this</span>.end = tokEnd;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
<span class="hljs-keyword">this</span>.loc = <span class="hljs-keyword">new</span> SourceLocation();
|
||
<span class="hljs-keyword">this</span>.loc.end = tokEndLoc;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-17">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-17">¶</a>
|
||
</div>
|
||
<p>TODO: remove in next major release</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.startLoc = tokStartLoc;
|
||
<span class="hljs-keyword">this</span>.endLoc = tokEndLoc;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.ranges)
|
||
<span class="hljs-keyword">this</span>.range = [tokStart, tokEnd];
|
||
}
|
||
|
||
exports.Token = Token;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-18">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-18">¶</a>
|
||
</div>
|
||
<p>Acorn is organized as a tokenizer and a recursive-descent parser.
|
||
The <code>tokenize</code> export provides an interface to the tokenizer.
|
||
Because the tokenizer is optimized for being efficiently used by
|
||
the Acorn parser itself, this interface is somewhat crude and not
|
||
very modular. Performing another parse or call to <code>tokenize</code> will
|
||
reset the internal state, and invalidate existing tokenizers.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
exports.tokenize = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(inpt, opts)</span> </span>{
|
||
input = <span class="hljs-built_in">String</span>(inpt); inputLen = input.length;
|
||
setOptions(opts);
|
||
initTokenState();
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getToken</span><span class="hljs-params">(forceRegexp)</span> </span>{
|
||
lastEnd = tokEnd;
|
||
readToken(forceRegexp);
|
||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Token();
|
||
}
|
||
getToken.jumpTo = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(pos, reAllowed)</span> </span>{
|
||
tokPos = pos;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
tokCurLine = <span class="hljs-number">1</span>;
|
||
tokLineStart = lineBreak.lastIndex = <span class="hljs-number">0</span>;
|
||
<span class="hljs-keyword">var</span> match;
|
||
<span class="hljs-keyword">while</span> ((match = lineBreak.exec(input)) && match.index < pos) {
|
||
++tokCurLine;
|
||
tokLineStart = match.index + match[<span class="hljs-number">0</span>].length;
|
||
}
|
||
}
|
||
tokRegexpAllowed = reAllowed;
|
||
skipSpace();
|
||
};
|
||
<span class="hljs-keyword">return</span> getToken;
|
||
};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-19">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-19">¶</a>
|
||
</div>
|
||
<p>State is kept in (closure-)global variables. We already saw the
|
||
<code>options</code>, <code>input</code>, and <code>inputLen</code> variables above.</p>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-20">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-20">¶</a>
|
||
</div>
|
||
<p>The current position of the tokenizer in the input.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokPos;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-21">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-21">¶</a>
|
||
</div>
|
||
<p>The start and end offsets of the current token.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokStart, tokEnd;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-22">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-22">¶</a>
|
||
</div>
|
||
<p>When <code>options.locations</code> is true, these hold objects
|
||
containing the tokens start and end line/column pairs.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokStartLoc, tokEndLoc;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-23">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-23">¶</a>
|
||
</div>
|
||
<p>The type and value of the current token. Token types are objects,
|
||
named by variables against which they can be compared, and
|
||
holding properties that describe them (indicating, for example,
|
||
the precedence of an infix operator, and the original name of a
|
||
keyword token). The kind of value that’s held in <code>tokVal</code> depends
|
||
on the type of the token. For literals, it is the literal value,
|
||
for operators, the operator name, and so on.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokType, tokVal;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-24">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-24">¶</a>
|
||
</div>
|
||
<p>Internal state for the tokenizer. To distinguish between division
|
||
operators and regular expressions, it remembers whether the last
|
||
token was one that is allowed to be followed by an expression.
|
||
(If it is, a slash is probably a regexp, if it isn’t it’s a
|
||
division operator. See the <code>parseStatement</code> function for a
|
||
caveat.)</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokRegexpAllowed;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-25">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-25">¶</a>
|
||
</div>
|
||
<p>When <code>options.locations</code> is true, these are used to keep
|
||
track of the current line, and know when a new line has been
|
||
entered.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> tokCurLine, tokLineStart;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-26">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-26">¶</a>
|
||
</div>
|
||
<p>These store the position of the previous token, which is useful
|
||
when finishing a node and assigning its <code>end</code> position.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> lastStart, lastEnd, lastEndLoc;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-27">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-27">¶</a>
|
||
</div>
|
||
<p>This is the parser’s state. <code>inFunction</code> is used to reject
|
||
<code>return</code> statements outside of functions, <code>inGenerator</code> to
|
||
reject <code>yield</code>s outside of generators, <code>labels</code> to verify
|
||
that <code>break</code> and <code>continue</code> have somewhere to jump to, and
|
||
<code>strict</code> indicates whether strict mode is on.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> inFunction, inGenerator, labels, strict, inXJSChild, inXJSTag;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-28">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-28">¶</a>
|
||
</div>
|
||
<p>This counter is used for checking that arrow expressions did
|
||
not contain nested parentheses in argument list.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> metParenL;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-29">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-29">¶</a>
|
||
</div>
|
||
<p>This is used by parser for detecting if it’s inside ES6
|
||
Template String. If it is, it should treat ‘$’ as prefix before
|
||
‘{expression}’ and everything else as string literals.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> inTemplate;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-30">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-30">¶</a>
|
||
</div>
|
||
<p>This function is used to raise exceptions on parse errors. It
|
||
takes an offset integer (into the current <code>input</code>) to indicate
|
||
the location of the error, attaches the position to the end
|
||
of the error message, and then raises a <code>SyntaxError</code> with that
|
||
message.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">raise</span><span class="hljs-params">(pos, message)</span> </span>{
|
||
<span class="hljs-keyword">var</span> loc = getLineInfo(input, pos);
|
||
message += <span class="hljs-string">" ("</span> + loc.line + <span class="hljs-string">":"</span> + loc.column + <span class="hljs-string">")"</span>;
|
||
<span class="hljs-keyword">var</span> err = <span class="hljs-keyword">new</span> <span class="hljs-built_in">SyntaxError</span>(message);
|
||
err.pos = pos; err.loc = loc; err.raisedAt = tokPos;
|
||
<span class="hljs-keyword">throw</span> err;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-31">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-31">¶</a>
|
||
</div>
|
||
<p>Reused empty array added for node fields that are always empty.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> empty = [];</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-32">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-32">¶</a>
|
||
</div>
|
||
<h2 id="token-types">Token types</h2>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-33">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-33">¶</a>
|
||
</div>
|
||
<p>The assignment of fine-grained, information-carrying type objects
|
||
allows the tokenizer to store the information it has about a
|
||
token in a way that is very cheap for the parser to look up.</p>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-34">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-34">¶</a>
|
||
</div>
|
||
<p>All token type variables start with an underscore, to make them
|
||
easy to recognize.</p>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-35">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-35">¶</a>
|
||
</div>
|
||
<p>These are the general types. The <code>type</code> property is only used to
|
||
make them recognizeable when debugging.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _num = {type: <span class="hljs-string">"num"</span>}, _regexp = {type: <span class="hljs-string">"regexp"</span>}, _string = {type: <span class="hljs-string">"string"</span>};
|
||
<span class="hljs-keyword">var</span> _name = {type: <span class="hljs-string">"name"</span>}, _eof = {type: <span class="hljs-string">"eof"</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-36">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-36">¶</a>
|
||
</div>
|
||
<p>These are JSX-specific token types</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _xjsName = {type: <span class="hljs-string">"xjsName"</span>}, _xjsText = {type: <span class="hljs-string">"xjsText"</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-37">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-37">¶</a>
|
||
</div>
|
||
<p>Keyword tokens. The <code>keyword</code> property (also used in keyword-like
|
||
operators) indicates that the token originated from an
|
||
identifier-like word, which is used when parsing property names.</p>
|
||
<p>The <code>beforeExpr</code> property is used to disambiguate between regular
|
||
expressions and divisions. It is set on all token types that can
|
||
be followed by an expression (thus, a slash after them would be a
|
||
regular expression).</p>
|
||
<p><code>isLoop</code> marks a keyword as starting a loop, which is important
|
||
to know when parsing a label, in order to allow or disallow
|
||
continue jumps to that label.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _break = {keyword: <span class="hljs-string">"break"</span>}, _case = {keyword: <span class="hljs-string">"case"</span>, beforeExpr: <span class="hljs-literal">true</span>}, _catch = {keyword: <span class="hljs-string">"catch"</span>};
|
||
<span class="hljs-keyword">var</span> _continue = {keyword: <span class="hljs-string">"continue"</span>}, _debugger = {keyword: <span class="hljs-string">"debugger"</span>}, _default = {keyword: <span class="hljs-string">"default"</span>};
|
||
<span class="hljs-keyword">var</span> _do = {keyword: <span class="hljs-string">"do"</span>, isLoop: <span class="hljs-literal">true</span>}, _else = {keyword: <span class="hljs-string">"else"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _finally = {keyword: <span class="hljs-string">"finally"</span>}, _for = {keyword: <span class="hljs-string">"for"</span>, isLoop: <span class="hljs-literal">true</span>}, _function = {keyword: <span class="hljs-string">"function"</span>};
|
||
<span class="hljs-keyword">var</span> _if = {keyword: <span class="hljs-string">"if"</span>}, _return = {keyword: <span class="hljs-string">"return"</span>, beforeExpr: <span class="hljs-literal">true</span>}, _switch = {keyword: <span class="hljs-string">"switch"</span>};
|
||
<span class="hljs-keyword">var</span> _throw = {keyword: <span class="hljs-string">"throw"</span>, beforeExpr: <span class="hljs-literal">true</span>}, _try = {keyword: <span class="hljs-string">"try"</span>}, _var = {keyword: <span class="hljs-string">"var"</span>};
|
||
<span class="hljs-keyword">var</span> _let = {keyword: <span class="hljs-string">"let"</span>}, _const = {keyword: <span class="hljs-string">"const"</span>};
|
||
<span class="hljs-keyword">var</span> _while = {keyword: <span class="hljs-string">"while"</span>, isLoop: <span class="hljs-literal">true</span>}, _with = {keyword: <span class="hljs-string">"with"</span>}, _new = {keyword: <span class="hljs-string">"new"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _this = {keyword: <span class="hljs-string">"this"</span>};
|
||
<span class="hljs-keyword">var</span> _class = {keyword: <span class="hljs-string">"class"</span>}, _extends = {keyword: <span class="hljs-string">"extends"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _export = {keyword: <span class="hljs-string">"export"</span>}, _import = {keyword: <span class="hljs-string">"import"</span>};
|
||
<span class="hljs-keyword">var</span> _yield = {keyword: <span class="hljs-string">"yield"</span>, beforeExpr: <span class="hljs-literal">true</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-38">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-38">¶</a>
|
||
</div>
|
||
<p>The keywords that denote values.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _null = {keyword: <span class="hljs-string">"null"</span>, atomValue: <span class="hljs-literal">null</span>}, _true = {keyword: <span class="hljs-string">"true"</span>, atomValue: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _false = {keyword: <span class="hljs-string">"false"</span>, atomValue: <span class="hljs-literal">false</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-39">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-39">¶</a>
|
||
</div>
|
||
<p>Some keywords are treated as regular operators. <code>in</code> sometimes
|
||
(when parsing <code>for</code>) needs to be tested against specifically, so
|
||
we assign a variable name to it for quick comparing.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _in = {keyword: <span class="hljs-string">"in"</span>, binop: <span class="hljs-number">7</span>, beforeExpr: <span class="hljs-literal">true</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-40">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-40">¶</a>
|
||
</div>
|
||
<p>Map keyword names to token types.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> keywordTypes = {<span class="hljs-string">"break"</span>: _break, <span class="hljs-string">"case"</span>: _case, <span class="hljs-string">"catch"</span>: _catch,
|
||
<span class="hljs-string">"continue"</span>: _continue, <span class="hljs-string">"debugger"</span>: _debugger, <span class="hljs-string">"default"</span>: _default,
|
||
<span class="hljs-string">"do"</span>: _do, <span class="hljs-string">"else"</span>: _else, <span class="hljs-string">"finally"</span>: _finally, <span class="hljs-string">"for"</span>: _for,
|
||
<span class="hljs-string">"function"</span>: _function, <span class="hljs-string">"if"</span>: _if, <span class="hljs-string">"return"</span>: _return, <span class="hljs-string">"switch"</span>: _switch,
|
||
<span class="hljs-string">"throw"</span>: _throw, <span class="hljs-string">"try"</span>: _try, <span class="hljs-string">"var"</span>: _var, <span class="hljs-string">"let"</span>: _let, <span class="hljs-string">"const"</span>: _const,
|
||
<span class="hljs-string">"while"</span>: _while, <span class="hljs-string">"with"</span>: _with,
|
||
<span class="hljs-string">"null"</span>: _null, <span class="hljs-string">"true"</span>: _true, <span class="hljs-string">"false"</span>: _false, <span class="hljs-string">"new"</span>: _new, <span class="hljs-string">"in"</span>: _in,
|
||
<span class="hljs-string">"instanceof"</span>: {keyword: <span class="hljs-string">"instanceof"</span>, binop: <span class="hljs-number">7</span>, beforeExpr: <span class="hljs-literal">true</span>}, <span class="hljs-string">"this"</span>: _this,
|
||
<span class="hljs-string">"typeof"</span>: {keyword: <span class="hljs-string">"typeof"</span>, prefix: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>},
|
||
<span class="hljs-string">"void"</span>: {keyword: <span class="hljs-string">"void"</span>, prefix: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>},
|
||
<span class="hljs-string">"delete"</span>: {keyword: <span class="hljs-string">"delete"</span>, prefix: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>},
|
||
<span class="hljs-string">"class"</span>: _class, <span class="hljs-string">"extends"</span>: _extends,
|
||
<span class="hljs-string">"export"</span>: _export, <span class="hljs-string">"import"</span>: _import, <span class="hljs-string">"yield"</span>: _yield};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-41">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-41">¶</a>
|
||
</div>
|
||
<p>Punctuation token types. Again, the <code>type</code> property is purely for debugging.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _bracketL = {type: <span class="hljs-string">"["</span>, beforeExpr: <span class="hljs-literal">true</span>}, _bracketR = {type: <span class="hljs-string">"]"</span>}, _braceL = {type: <span class="hljs-string">"{"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _braceR = {type: <span class="hljs-string">"}"</span>}, _parenL = {type: <span class="hljs-string">"("</span>, beforeExpr: <span class="hljs-literal">true</span>}, _parenR = {type: <span class="hljs-string">")"</span>};
|
||
<span class="hljs-keyword">var</span> _comma = {type: <span class="hljs-string">","</span>, beforeExpr: <span class="hljs-literal">true</span>}, _semi = {type: <span class="hljs-string">";"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _colon = {type: <span class="hljs-string">":"</span>, beforeExpr: <span class="hljs-literal">true</span>}, _dot = {type: <span class="hljs-string">"."</span>}, _ellipsis = {type: <span class="hljs-string">"..."</span>}, _question = {type: <span class="hljs-string">"?"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _arrow = {type: <span class="hljs-string">"=>"</span>, beforeExpr: <span class="hljs-literal">true</span>}, _bquote = {type: <span class="hljs-string">"`"</span>}, _dollarBraceL = {type: <span class="hljs-string">"${"</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _ltSlash = {type: <span class="hljs-string">"</"</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-42">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-42">¶</a>
|
||
</div>
|
||
<p>Operators. These carry several kinds of properties to help the
|
||
parser use them properly (the presence of these properties is
|
||
what categorizes them as operators).</p>
|
||
<p><code>binop</code>, when present, specifies that this operator is a binary
|
||
operator, and will refer to its precedence.</p>
|
||
<p><code>prefix</code> and <code>postfix</code> mark the operator as a prefix or postfix
|
||
unary operator. <code>isUpdate</code> specifies that the node produced by
|
||
the operator should be of type UpdateExpression rather than
|
||
simply UnaryExpression (<code>++</code> and <code>--</code>).</p>
|
||
<p><code>isAssign</code> marks all of <code>=</code>, <code>+=</code>, <code>-=</code> etcetera, which act as
|
||
binary operators with a very low precedence, that should result
|
||
in AssignmentExpression nodes.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> _slash = {binop: <span class="hljs-number">10</span>, beforeExpr: <span class="hljs-literal">true</span>}, _eq = {isAssign: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _assign = {isAssign: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _incDec = {postfix: <span class="hljs-literal">true</span>, prefix: <span class="hljs-literal">true</span>, isUpdate: <span class="hljs-literal">true</span>}, _prefix = {prefix: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _logicalOR = {binop: <span class="hljs-number">1</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _logicalAND = {binop: <span class="hljs-number">2</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _bitwiseOR = {binop: <span class="hljs-number">3</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _bitwiseXOR = {binop: <span class="hljs-number">4</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _bitwiseAND = {binop: <span class="hljs-number">5</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _equality = {binop: <span class="hljs-number">6</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _relational = {binop: <span class="hljs-number">7</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _bitShift = {binop: <span class="hljs-number">8</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _plusMin = {binop: <span class="hljs-number">9</span>, prefix: <span class="hljs-literal">true</span>, beforeExpr: <span class="hljs-literal">true</span>};
|
||
<span class="hljs-keyword">var</span> _modulo = {binop: <span class="hljs-number">10</span>, beforeExpr: <span class="hljs-literal">true</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-43">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-43">¶</a>
|
||
</div>
|
||
<p>‘*’ may be multiply or have special meaning in ES6</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> _star = {binop: <span class="hljs-number">10</span>, beforeExpr: <span class="hljs-literal">true</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-44">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-44">¶</a>
|
||
</div>
|
||
<p>‘<’, ‘>’ may be relational or have special meaning in JSX</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> _lt = {binop: <span class="hljs-number">7</span>, beforeExpr: <span class="hljs-literal">true</span>}, _gt = {binop: <span class="hljs-number">7</span>, beforeExpr: <span class="hljs-literal">true</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-45">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-45">¶</a>
|
||
</div>
|
||
<p>Provide access to the token types for external users of the
|
||
tokenizer.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
exports.tokTypes = {bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR,
|
||
parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon,
|
||
dot: _dot, ellipsis: _ellipsis, question: _question, slash: _slash, eq: _eq,
|
||
name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string,
|
||
arrow: _arrow, bquote: _bquote, dollarBraceL: _dollarBraceL,
|
||
xjsName: _xjsName, xjsText: _xjsText};
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> kw <span class="hljs-keyword">in</span> keywordTypes) exports.tokTypes[<span class="hljs-string">"_"</span> + kw] = keywordTypes[kw];</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-46">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-46">¶</a>
|
||
</div>
|
||
<p>This is a trick taken from Esprima. It turns out that, on
|
||
non-Chrome browsers, to check whether a string is in a set, a
|
||
predicate containing a big ugly <code>switch</code> statement is faster than
|
||
a regular expression, and on Chrome the two are about on par.
|
||
This function uses <code>eval</code> (non-lexical) to produce such a
|
||
predicate from a space-separated string of words.</p>
|
||
<p>It starts by sorting the words by length.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makePredicate</span><span class="hljs-params">(words)</span> </span>{
|
||
words = words.split(<span class="hljs-string">" "</span>);
|
||
<span class="hljs-keyword">var</span> f = <span class="hljs-string">""</span>, cats = [];
|
||
out: <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < words.length; ++i) {
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j < cats.length; ++j)
|
||
<span class="hljs-keyword">if</span> (cats[j][<span class="hljs-number">0</span>].length == words[i].length) {
|
||
cats[j].push(words[i]);
|
||
<span class="hljs-keyword">continue</span> out;
|
||
}
|
||
cats.push([words[i]]);
|
||
}
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compareTo</span><span class="hljs-params">(arr)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (arr.length == <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> f += <span class="hljs-string">"return str === "</span> + <span class="hljs-built_in">JSON</span>.stringify(arr[<span class="hljs-number">0</span>]) + <span class="hljs-string">";"</span>;
|
||
f += <span class="hljs-string">"switch(str){"</span>;
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < arr.length; ++i) f += <span class="hljs-string">"case "</span> + <span class="hljs-built_in">JSON</span>.stringify(arr[i]) + <span class="hljs-string">":"</span>;
|
||
f += <span class="hljs-string">"return true}return false;"</span>;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-47">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-47">¶</a>
|
||
</div>
|
||
<p>When there are more than three length categories, an outer
|
||
switch first dispatches on the lengths, to save on comparisons.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">if</span> (cats.length > <span class="hljs-number">3</span>) {
|
||
cats.sort(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(a, b)</span> </span>{<span class="hljs-keyword">return</span> b.length - a.length;});
|
||
f += <span class="hljs-string">"switch(str.length){"</span>;
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < cats.length; ++i) {
|
||
<span class="hljs-keyword">var</span> cat = cats[i];
|
||
f += <span class="hljs-string">"case "</span> + cat[<span class="hljs-number">0</span>].length + <span class="hljs-string">":"</span>;
|
||
compareTo(cat);
|
||
}
|
||
f += <span class="hljs-string">"}"</span>;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-48">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-48">¶</a>
|
||
</div>
|
||
<p>Otherwise, simply generate a flat <code>switch</code> statement.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
} <span class="hljs-keyword">else</span> {
|
||
compareTo(words);
|
||
}
|
||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Function</span>(<span class="hljs-string">"str"</span>, f);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-49">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-49">¶</a>
|
||
</div>
|
||
<p>The ECMAScript 3 reserved word list.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isReservedWord3 = makePredicate(<span class="hljs-string">"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-50">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-50">¶</a>
|
||
</div>
|
||
<p>ECMAScript 5 reserved words.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isReservedWord5 = makePredicate(<span class="hljs-string">"class enum extends super const export import"</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-51">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-51">¶</a>
|
||
</div>
|
||
<p>The additional reserved words in strict mode.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isStrictReservedWord = makePredicate(<span class="hljs-string">"implements interface let package private protected public static yield"</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-52">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-52">¶</a>
|
||
</div>
|
||
<p>The forbidden variable names in strict mode.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isStrictBadIdWord = makePredicate(<span class="hljs-string">"eval arguments"</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-53">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-53">¶</a>
|
||
</div>
|
||
<p>And the keywords.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> ecma5AndLessKeywords = <span class="hljs-string">"break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"</span>;
|
||
|
||
<span class="hljs-keyword">var</span> isEcma5AndLessKeyword = makePredicate(ecma5AndLessKeywords);
|
||
|
||
<span class="hljs-keyword">var</span> isEcma6Keyword = makePredicate(ecma5AndLessKeywords + <span class="hljs-string">" let const class extends export import yield"</span>);
|
||
|
||
<span class="hljs-keyword">var</span> isKeyword = isEcma5AndLessKeyword;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-54">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-54">¶</a>
|
||
</div>
|
||
<h2 id="character-categories">Character categories</h2>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-55">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-55">¶</a>
|
||
</div>
|
||
<p>Big ugly regular expressions that match characters in the
|
||
whitespace, identifier, and identifier-start categories. These
|
||
are only applied when a character is found to actually have a
|
||
code point above 128.
|
||
Generated by <code>tools/generate-identifier-regex.js</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> nonASCIIwhitespace = <span class="hljs-regexp">/[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/</span>;
|
||
<span class="hljs-keyword">var</span> nonASCIIidentifierStartChars = <span class="hljs-string">"\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC"</span>;
|
||
<span class="hljs-keyword">var</span> nonASCIIidentifierChars = <span class="hljs-string">"\u0300-\u036F\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u0669\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u06F0-\u06F9\u0711\u0730-\u074A\u07A6-\u07B0\u07C0-\u07C9\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0966-\u096F\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09E6-\u09EF\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A66-\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B66-\u0B6F\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0CE6-\u0CEF\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D66-\u0D6F\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0E50-\u0E59\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0ED0-\u0ED9\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1040-\u1049\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u18A9\u1920-\u192B\u1930-\u193B\u1946-\u194F\u19B0-\u19C0\u19C8\u19C9\u19D0-\u19D9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AB0-\u1ABD\u1B00-\u1B04\u1B34-\u1B44\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BB0-\u1BB9\u1BE6-\u1BF3\u1C24-\u1C37\u1C40-\u1C49\u1C50-\u1C59\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFC-\u1DFF\u200C\u200D\u203F\u2040\u2054\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA620-\uA629\uA66F\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F1\uA900-\uA909\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9D0-\uA9D9\uA9E5\uA9F0-\uA9F9\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA50-\uAA59\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uABF0-\uABF9\uFB1E\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFF10-\uFF19\uFF3F"</span>;
|
||
<span class="hljs-keyword">var</span> nonASCIIidentifierStart = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"["</span> + nonASCIIidentifierStartChars + <span class="hljs-string">"]"</span>);
|
||
<span class="hljs-keyword">var</span> nonASCIIidentifier = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"["</span> + nonASCIIidentifierStartChars + nonASCIIidentifierChars + <span class="hljs-string">"]"</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-56">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-56">¶</a>
|
||
</div>
|
||
<p>Whether a single character denotes a newline.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> newline = <span class="hljs-regexp">/[\n\r\u2028\u2029]/</span>;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-57">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-57">¶</a>
|
||
</div>
|
||
<p>Matches a whole line break (where CRLF is considered a single
|
||
line break). Used to count lines.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> lineBreak = <span class="hljs-regexp">/\r\n|[\n\r\u2028\u2029]/g</span>;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-58">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-58">¶</a>
|
||
</div>
|
||
<p>Test whether a given character code starts an identifier.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isIdentifierStart = exports.isIdentifierStart = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(code)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">65</span>) <span class="hljs-keyword">return</span> code === <span class="hljs-number">36</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">91</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">97</span>) <span class="hljs-keyword">return</span> code === <span class="hljs-number">95</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">123</span>)<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">return</span> code >= <span class="hljs-number">0xaa</span> && nonASCIIidentifierStart.test(<span class="hljs-built_in">String</span>.fromCharCode(code));
|
||
};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-59">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-59">¶</a>
|
||
</div>
|
||
<p>Test whether a given character is part of an identifier.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> isIdentifierChar = exports.isIdentifierChar = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(code)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">48</span>) <span class="hljs-keyword">return</span> code === <span class="hljs-number">36</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">58</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">65</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">91</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">97</span>) <span class="hljs-keyword">return</span> code === <span class="hljs-number">95</span>;
|
||
<span class="hljs-keyword">if</span> (code < <span class="hljs-number">123</span>)<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">return</span> code >= <span class="hljs-number">0xaa</span> && nonASCIIidentifier.test(<span class="hljs-built_in">String</span>.fromCharCode(code));
|
||
};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-60">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-60">¶</a>
|
||
</div>
|
||
<h2 id="tokenizer">Tokenizer</h2>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-61">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-61">¶</a>
|
||
</div>
|
||
<p>These are used when <code>options.locations</code> is on, for the
|
||
<code>tokStartLoc</code> and <code>tokEndLoc</code> properties.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Position</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">this</span>.line = tokCurLine;
|
||
<span class="hljs-keyword">this</span>.column = tokPos - tokLineStart;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-62">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-62">¶</a>
|
||
</div>
|
||
<p>Reset the token state. Used at the start of a parse.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initTokenState</span><span class="hljs-params">()</span> </span>{
|
||
tokCurLine = <span class="hljs-number">1</span>;
|
||
tokPos = tokLineStart = <span class="hljs-number">0</span>;
|
||
tokRegexpAllowed = <span class="hljs-literal">true</span>;
|
||
metParenL = <span class="hljs-number">0</span>;
|
||
inTemplate = inXJSChild = inXJSTag = <span class="hljs-literal">false</span>;
|
||
skipSpace();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-63">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-63">¶</a>
|
||
</div>
|
||
<p>Called at the end of every token. Sets <code>tokEnd</code>, <code>tokVal</code>, and
|
||
<code>tokRegexpAllowed</code>, and skips the space after the token, so that
|
||
the next one’s <code>tokStart</code> will point at the right position.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finishToken</span><span class="hljs-params">(type, val, shouldSkipSpace)</span> </span>{
|
||
tokEnd = tokPos;
|
||
<span class="hljs-keyword">if</span> (options.locations) tokEndLoc = <span class="hljs-keyword">new</span> Position;
|
||
tokType = type;
|
||
<span class="hljs-keyword">if</span> (shouldSkipSpace !== <span class="hljs-literal">false</span> && !(inXJSTag && type === _gt) && !(inXJSChild && tokType !== _braceL)) {
|
||
skipSpace();
|
||
}
|
||
tokVal = val;
|
||
tokRegexpAllowed = type.beforeExpr;
|
||
<span class="hljs-keyword">if</span> (options.onToken) {
|
||
options.onToken(<span class="hljs-keyword">new</span> Token());
|
||
}
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">skipBlockComment</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> startLoc = options.onComment && options.locations && <span class="hljs-keyword">new</span> Position;
|
||
<span class="hljs-keyword">var</span> start = tokPos, end = input.indexOf(<span class="hljs-string">"*/"</span>, tokPos += <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">if</span> (end === -<span class="hljs-number">1</span>) raise(tokPos - <span class="hljs-number">2</span>, <span class="hljs-string">"Unterminated comment"</span>);
|
||
tokPos = end + <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
lineBreak.lastIndex = start;
|
||
<span class="hljs-keyword">var</span> match;
|
||
<span class="hljs-keyword">while</span> ((match = lineBreak.exec(input)) && match.index < tokPos) {
|
||
++tokCurLine;
|
||
tokLineStart = match.index + match[<span class="hljs-number">0</span>].length;
|
||
}
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.onComment)
|
||
options.onComment(<span class="hljs-literal">true</span>, input.slice(start + <span class="hljs-number">2</span>, end), start, tokPos,
|
||
startLoc, options.locations && <span class="hljs-keyword">new</span> Position);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">skipLineComment</span><span class="hljs-params">(startSkip)</span> </span>{
|
||
<span class="hljs-keyword">var</span> start = tokPos;
|
||
<span class="hljs-keyword">var</span> startLoc = options.onComment && options.locations && <span class="hljs-keyword">new</span> Position;
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos+=startSkip);
|
||
<span class="hljs-keyword">while</span> (tokPos < inputLen && ch !== <span class="hljs-number">10</span> && ch !== <span class="hljs-number">13</span> && ch !== <span class="hljs-number">8232</span> && ch !== <span class="hljs-number">8233</span>) {
|
||
++tokPos;
|
||
ch = input.charCodeAt(tokPos);
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.onComment)
|
||
options.onComment(<span class="hljs-literal">false</span>, input.slice(start + startSkip, tokPos), start, tokPos,
|
||
startLoc, options.locations && <span class="hljs-keyword">new</span> Position);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-64">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-64">¶</a>
|
||
</div>
|
||
<p>Called at the start of the parse and after every token. Skips
|
||
whitespace and comments, and.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">skipSpace</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">while</span> (tokPos < inputLen) {
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">32</span>) { <span class="hljs-comment">// ' '</span>
|
||
++tokPos;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-number">13</span>) {
|
||
++tokPos;
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">10</span>) {
|
||
++tokPos;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
++tokCurLine;
|
||
tokLineStart = tokPos;
|
||
}
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-number">10</span> || ch === <span class="hljs-number">8232</span> || ch === <span class="hljs-number">8233</span>) {
|
||
++tokPos;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
++tokCurLine;
|
||
tokLineStart = tokPos;
|
||
}
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch > <span class="hljs-number">8</span> && ch < <span class="hljs-number">14</span>) {
|
||
++tokPos;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-number">47</span>) { <span class="hljs-comment">// '/'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">42</span>) { <span class="hljs-comment">// '*'</span>
|
||
skipBlockComment();
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (next === <span class="hljs-number">47</span>) { <span class="hljs-comment">// '/'</span>
|
||
skipLineComment(<span class="hljs-number">2</span>);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-number">160</span>) { <span class="hljs-comment">// '\xa0'</span>
|
||
++tokPos;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch >= <span class="hljs-number">5760</span> && nonASCIIwhitespace.test(<span class="hljs-built_in">String</span>.fromCharCode(ch))) {
|
||
++tokPos;
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-65">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-65">¶</a>
|
||
</div>
|
||
<h3 id="token-reading">Token reading</h3>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-66">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-66">¶</a>
|
||
</div>
|
||
<p>This is the function that is called to fetch the next token. It
|
||
is somewhat obscure, because it works in character codes rather
|
||
than characters, and because operator parsing has been inlined
|
||
into it.</p>
|
||
<p>All in the name of speed.</p>
|
||
<p>The <code>forceRegexp</code> parameter is used in the one case where the
|
||
<code>tokRegexpAllowed</code> trick does not work. See <code>parseStatement</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_dot</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next >= <span class="hljs-number">48</span> && next <= <span class="hljs-number">57</span>) <span class="hljs-keyword">return</span> readNumber(<span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">var</span> next2 = input.charCodeAt(tokPos + <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && next === <span class="hljs-number">46</span> && next2 === <span class="hljs-number">46</span>) { <span class="hljs-comment">// 46 = dot '.'</span>
|
||
tokPos += <span class="hljs-number">3</span>;
|
||
<span class="hljs-keyword">return</span> finishToken(_ellipsis);
|
||
} <span class="hljs-keyword">else</span> {
|
||
++tokPos;
|
||
<span class="hljs-keyword">return</span> finishToken(_dot);
|
||
}
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_slash</span><span class="hljs-params">()</span> </span>{ <span class="hljs-comment">// '/'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (tokRegexpAllowed) {++tokPos; <span class="hljs-keyword">return</span> readRegexp();}
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(_slash, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_mult_modulo</span><span class="hljs-params">(code)</span> </span>{ <span class="hljs-comment">// '%*'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(code === <span class="hljs-number">42</span> ? _star : _modulo, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_pipe_amp</span><span class="hljs-params">(code)</span> </span>{ <span class="hljs-comment">// '|&'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === code) <span class="hljs-keyword">return</span> finishOp(code === <span class="hljs-number">124</span> ? _logicalOR : _logicalAND, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(code === <span class="hljs-number">124</span> ? _bitwiseOR : _bitwiseAND, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_caret</span><span class="hljs-params">()</span> </span>{ <span class="hljs-comment">// '^'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(_bitwiseXOR, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_plus_min</span><span class="hljs-params">(code)</span> </span>{ <span class="hljs-comment">// '+-'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === code) {
|
||
<span class="hljs-keyword">if</span> (next == <span class="hljs-number">45</span> && input.charCodeAt(tokPos + <span class="hljs-number">2</span>) == <span class="hljs-number">62</span> &&
|
||
newline.test(input.slice(lastEnd, tokPos))) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-67">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-67">¶</a>
|
||
</div>
|
||
<p>A <code>--></code> line comment</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> skipLineComment(<span class="hljs-number">3</span>);
|
||
skipSpace();
|
||
<span class="hljs-keyword">return</span> readToken();
|
||
}
|
||
<span class="hljs-keyword">return</span> finishOp(_incDec, <span class="hljs-number">2</span>);
|
||
}
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(_plusMin, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_lt_gt</span><span class="hljs-params">(code)</span> </span>{ <span class="hljs-comment">// '<>'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">var</span> size = <span class="hljs-number">1</span>;
|
||
<span class="hljs-keyword">if</span> (next === code) {
|
||
size = code === <span class="hljs-number">62</span> && input.charCodeAt(tokPos + <span class="hljs-number">2</span>) === <span class="hljs-number">62</span> ? <span class="hljs-number">3</span> : <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">if</span> (input.charCodeAt(tokPos + size) === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_assign, size + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">return</span> finishOp(_bitShift, size);
|
||
}
|
||
<span class="hljs-keyword">if</span> (next == <span class="hljs-number">33</span> && code == <span class="hljs-number">60</span> && input.charCodeAt(tokPos + <span class="hljs-number">2</span>) == <span class="hljs-number">45</span> &&
|
||
input.charCodeAt(tokPos + <span class="hljs-number">3</span>) == <span class="hljs-number">45</span>) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-68">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-68">¶</a>
|
||
</div>
|
||
<p><code><!--</code>, an XML-style comment that should be interpreted as a line comment</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> skipLineComment(<span class="hljs-number">4</span>);
|
||
skipSpace();
|
||
<span class="hljs-keyword">return</span> readToken();
|
||
}
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) {
|
||
size = input.charCodeAt(tokPos + <span class="hljs-number">2</span>) === <span class="hljs-number">61</span> ? <span class="hljs-number">3</span> : <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">return</span> finishOp(_relational, size);
|
||
}
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">47</span>) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-69">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-69">¶</a>
|
||
</div>
|
||
<p>‘</‘, beginning of JSX closing element</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> size = <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">return</span> finishOp(_ltSlash, size);
|
||
}
|
||
<span class="hljs-keyword">return</span> finishOp(code === <span class="hljs-number">60</span> ? _lt : _gt, size);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken_eq_excl</span><span class="hljs-params">(code)</span> </span>{ <span class="hljs-comment">// '=!', '=>'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">61</span>) <span class="hljs-keyword">return</span> finishOp(_equality, input.charCodeAt(tokPos + <span class="hljs-number">2</span>) === <span class="hljs-number">61</span> ? <span class="hljs-number">3</span> : <span class="hljs-number">2</span>);
|
||
<span class="hljs-keyword">if</span> (code === <span class="hljs-number">61</span> && next === <span class="hljs-number">62</span> && options.ecmaVersion >= <span class="hljs-number">6</span>) { <span class="hljs-comment">// '=>'</span>
|
||
tokPos += <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">return</span> finishToken(_arrow);
|
||
}
|
||
<span class="hljs-keyword">return</span> finishOp(code === <span class="hljs-number">61</span> ? _eq : _prefix, <span class="hljs-number">1</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-70">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-70">¶</a>
|
||
</div>
|
||
<p>Get token inside ES6 template (special rules work there).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTemplateToken</span><span class="hljs-params">(code)</span> </span>{</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-71">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-71">¶</a>
|
||
</div>
|
||
<p>‘`’ and ‘${‘ have special meanings, but they should follow
|
||
string (can be empty)</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tokType === _string) {
|
||
<span class="hljs-keyword">if</span> (code === <span class="hljs-number">96</span>) { <span class="hljs-comment">// '`'</span>
|
||
++tokPos;
|
||
<span class="hljs-keyword">return</span> finishToken(_bquote);
|
||
} <span class="hljs-keyword">else</span>
|
||
<span class="hljs-keyword">if</span> (code === <span class="hljs-number">36</span> && input.charCodeAt(tokPos + <span class="hljs-number">1</span>) === <span class="hljs-number">123</span>) { <span class="hljs-comment">// '${'</span>
|
||
tokPos += <span class="hljs-number">2</span>;
|
||
<span class="hljs-keyword">return</span> finishToken(_dollarBraceL);
|
||
}
|
||
}
|
||
|
||
<span class="hljs-keyword">if</span> (code === <span class="hljs-number">125</span>) { <span class="hljs-comment">// '}'</span>
|
||
++tokPos;
|
||
<span class="hljs-keyword">return</span> finishToken(_braceR, <span class="hljs-literal">undefined</span>, <span class="hljs-literal">false</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-72">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-72">¶</a>
|
||
</div>
|
||
<p>anything else is considered string literal</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> readTmplString();
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTokenFromCode</span><span class="hljs-params">(code)</span> </span>{
|
||
<span class="hljs-keyword">switch</span>(code) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-73">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-73">¶</a>
|
||
</div>
|
||
<p>The interpretation of a dot depends on whether it is followed
|
||
by a digit or another two dots.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-number">46</span>: <span class="hljs-comment">// '.'</span>
|
||
<span class="hljs-keyword">return</span> readToken_dot();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-74">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-74">¶</a>
|
||
</div>
|
||
<p>Punctuation tokens.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-number">40</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_parenL);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">41</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_parenR);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">59</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_semi);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">44</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_comma);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">91</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_bracketL);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">93</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_bracketR);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">123</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_braceL);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">125</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_braceR);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">58</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_colon);
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">63</span>: ++tokPos; <span class="hljs-keyword">return</span> finishToken(_question);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">96</span>: <span class="hljs-comment">// '`'</span>
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
++tokPos;
|
||
<span class="hljs-keyword">return</span> finishToken(_bquote, <span class="hljs-literal">undefined</span>, <span class="hljs-literal">false</span>);
|
||
}
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">48</span>: <span class="hljs-comment">// '0'</span>
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos + <span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">120</span> || next === <span class="hljs-number">88</span>) <span class="hljs-keyword">return</span> readRadixNumber(<span class="hljs-number">16</span>); <span class="hljs-comment">// '0x', '0X' - hex number</span>
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">111</span> || next === <span class="hljs-number">79</span>) <span class="hljs-keyword">return</span> readRadixNumber(<span class="hljs-number">8</span>); <span class="hljs-comment">// '0o', '0O' - octal number</span>
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">98</span> || next === <span class="hljs-number">66</span>) <span class="hljs-keyword">return</span> readRadixNumber(<span class="hljs-number">2</span>); <span class="hljs-comment">// '0b', '0B' - binary number</span>
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-75">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-75">¶</a>
|
||
</div>
|
||
<p>Anything else beginning with a digit is an integer, octal
|
||
number, or float.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-number">49</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">50</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">51</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">52</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">53</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">54</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">55</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">56</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">57</span>: <span class="hljs-comment">// 1-9</span>
|
||
<span class="hljs-keyword">return</span> readNumber(<span class="hljs-literal">false</span>);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-76">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-76">¶</a>
|
||
</div>
|
||
<p>Quotes produce strings.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-number">34</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">39</span>: <span class="hljs-comment">// '"', "'"</span>
|
||
<span class="hljs-keyword">return</span> inXJSTag ? readXJSStringLiteral() : readString(code);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-77">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-77">¶</a>
|
||
</div>
|
||
<p>Operators are parsed inline in tiny state machines. ‘=’ (61) is
|
||
often referred to. <code>finishOp</code> simply skips the amount of
|
||
characters it is given as second argument, and returns a token
|
||
of the type given by its first argument.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">47</span>: <span class="hljs-comment">// '/'</span>
|
||
<span class="hljs-keyword">return</span> readToken_slash();
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">37</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">42</span>: <span class="hljs-comment">// '%*'</span>
|
||
<span class="hljs-keyword">return</span> readToken_mult_modulo(code);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">124</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">38</span>: <span class="hljs-comment">// '|&'</span>
|
||
<span class="hljs-keyword">return</span> readToken_pipe_amp(code);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">94</span>: <span class="hljs-comment">// '^'</span>
|
||
<span class="hljs-keyword">return</span> readToken_caret();
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">43</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">45</span>: <span class="hljs-comment">// '+-'</span>
|
||
<span class="hljs-keyword">return</span> readToken_plus_min(code);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">60</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">62</span>: <span class="hljs-comment">// '<>'</span>
|
||
<span class="hljs-keyword">return</span> readToken_lt_gt(code);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">61</span>: <span class="hljs-keyword">case</span> <span class="hljs-number">33</span>: <span class="hljs-comment">// '=!'</span>
|
||
<span class="hljs-keyword">return</span> readToken_eq_excl(code);
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">126</span>: <span class="hljs-comment">// '~'</span>
|
||
<span class="hljs-keyword">return</span> finishOp(_prefix, <span class="hljs-number">1</span>);
|
||
}
|
||
|
||
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readToken</span><span class="hljs-params">(forceRegexp)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (!forceRegexp) tokStart = tokPos;
|
||
<span class="hljs-keyword">else</span> tokPos = tokStart + <span class="hljs-number">1</span>;
|
||
<span class="hljs-keyword">if</span> (options.locations) tokStartLoc = <span class="hljs-keyword">new</span> Position;
|
||
<span class="hljs-keyword">if</span> (forceRegexp) <span class="hljs-keyword">return</span> readRegexp();
|
||
<span class="hljs-keyword">if</span> (tokPos >= inputLen) <span class="hljs-keyword">return</span> finishToken(_eof);
|
||
|
||
<span class="hljs-keyword">var</span> code = input.charCodeAt(tokPos);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-78">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-78">¶</a>
|
||
</div>
|
||
<p>JSX content - either simple text, start of <tag> or {expression}</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (inXJSChild && tokType !== _braceL && code !== <span class="hljs-number">60</span> && code !== <span class="hljs-number">123</span> && code !== <span class="hljs-number">125</span>) {
|
||
<span class="hljs-keyword">return</span> readXJSText([<span class="hljs-string">'<'</span>, <span class="hljs-string">'{'</span>]);
|
||
}
|
||
|
||
|
||
<span class="hljs-keyword">if</span> (inTemplate) <span class="hljs-keyword">return</span> getTemplateToken(code);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-79">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-79">¶</a>
|
||
</div>
|
||
<p>Identifier or keyword. ‘\uXXXX’ sequences are allowed in
|
||
identifiers, so ‘\’ also dispatches to that.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (isIdentifierStart(code) || code === <span class="hljs-number">92</span> <span class="hljs-comment">/* '\' */</span>) <span class="hljs-keyword">return</span> readWord();
|
||
|
||
<span class="hljs-keyword">var</span> tok = getTokenFromCode(code);
|
||
|
||
<span class="hljs-keyword">if</span> (tok === <span class="hljs-literal">false</span>) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-80">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-80">¶</a>
|
||
</div>
|
||
<p>If we are here, we either found a non-ASCII identifier
|
||
character, or something that’s entirely disallowed.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> ch = <span class="hljs-built_in">String</span>.fromCharCode(code);
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-string">"\\"</span> || nonASCIIidentifierStart.test(ch)) <span class="hljs-keyword">return</span> readWord();
|
||
raise(tokPos, <span class="hljs-string">"Unexpected character '"</span> + ch + <span class="hljs-string">"'"</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> tok;
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finishOp</span><span class="hljs-params">(type, size)</span> </span>{
|
||
<span class="hljs-keyword">var</span> str = input.slice(tokPos, tokPos + size);
|
||
tokPos += size;
|
||
finishToken(type, str);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-81">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-81">¶</a>
|
||
</div>
|
||
<p>Parse a regular expression. Some context-awareness is necessary,
|
||
since a ‘/‘ inside a ‘[]’ set does not end the expression.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readRegexp</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> content = <span class="hljs-string">""</span>, escaped, inClass, start = tokPos;
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">if</span> (tokPos >= inputLen) raise(start, <span class="hljs-string">"Unterminated regular expression"</span>);
|
||
<span class="hljs-keyword">var</span> ch = nextChar();
|
||
<span class="hljs-keyword">if</span> (newline.test(ch)) raise(start, <span class="hljs-string">"Unterminated regular expression"</span>);
|
||
<span class="hljs-keyword">if</span> (!escaped) {
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-string">"["</span>) inClass = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-string">"]"</span> && inClass) inClass = <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-string">"/"</span> && !inClass) <span class="hljs-keyword">break</span>;
|
||
escaped = ch === <span class="hljs-string">"\\"</span>;
|
||
} <span class="hljs-keyword">else</span> escaped = <span class="hljs-literal">false</span>;
|
||
++tokPos;
|
||
}
|
||
<span class="hljs-keyword">var</span> content = input.slice(start, tokPos);
|
||
++tokPos;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-82">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-82">¶</a>
|
||
</div>
|
||
<p>Need to use <code>readWord1</code> because ‘\uXXXX’ sequences are allowed
|
||
here (don’t ask).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> mods = readWord1();
|
||
<span class="hljs-keyword">if</span> (mods && !<span class="hljs-regexp">/^[gmsiy]*$/</span>.test(mods)) raise(start, <span class="hljs-string">"Invalid regular expression flag"</span>);
|
||
<span class="hljs-keyword">try</span> {
|
||
<span class="hljs-keyword">var</span> value = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(content, mods);
|
||
} <span class="hljs-keyword">catch</span> (e) {
|
||
<span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">SyntaxError</span>) raise(start, <span class="hljs-string">"Error parsing regular expression: "</span> + e.message);
|
||
raise(e);
|
||
}
|
||
<span class="hljs-keyword">return</span> finishToken(_regexp, value);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-83">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-83">¶</a>
|
||
</div>
|
||
<p>Read an integer in the given radix. Return null if zero digits
|
||
were read, the integer value otherwise. When <code>len</code> is given, this
|
||
will return <code>null</code> unless the integer has exactly <code>len</code> digits.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readInt</span><span class="hljs-params">(radix, len)</span> </span>{
|
||
<span class="hljs-keyword">var</span> start = tokPos, total = <span class="hljs-number">0</span>;
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, e = len == <span class="hljs-literal">null</span> ? <span class="hljs-literal">Infinity</span> : len; i < e; ++i) {
|
||
<span class="hljs-keyword">var</span> code = input.charCodeAt(tokPos), val;
|
||
<span class="hljs-keyword">if</span> (code >= <span class="hljs-number">97</span>) val = code - <span class="hljs-number">97</span> + <span class="hljs-number">10</span>; <span class="hljs-comment">// a</span>
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (code >= <span class="hljs-number">65</span>) val = code - <span class="hljs-number">65</span> + <span class="hljs-number">10</span>; <span class="hljs-comment">// A</span>
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (code >= <span class="hljs-number">48</span> && code <= <span class="hljs-number">57</span>) val = code - <span class="hljs-number">48</span>; <span class="hljs-comment">// 0-9</span>
|
||
<span class="hljs-keyword">else</span> val = <span class="hljs-literal">Infinity</span>;
|
||
<span class="hljs-keyword">if</span> (val >= radix) <span class="hljs-keyword">break</span>;
|
||
++tokPos;
|
||
total = total * radix + val;
|
||
}
|
||
<span class="hljs-keyword">if</span> (tokPos === start || len != <span class="hljs-literal">null</span> && tokPos - start !== len) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
|
||
|
||
<span class="hljs-keyword">return</span> total;
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readRadixNumber</span><span class="hljs-params">(radix)</span> </span>{
|
||
tokPos += <span class="hljs-number">2</span>; <span class="hljs-comment">// 0x</span>
|
||
<span class="hljs-keyword">var</span> val = readInt(radix);
|
||
<span class="hljs-keyword">if</span> (val == <span class="hljs-literal">null</span>) raise(tokStart + <span class="hljs-number">2</span>, <span class="hljs-string">"Expected number in radix "</span> + radix);
|
||
<span class="hljs-keyword">if</span> (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, <span class="hljs-string">"Identifier directly after number"</span>);
|
||
<span class="hljs-keyword">return</span> finishToken(_num, val);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-84">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-84">¶</a>
|
||
</div>
|
||
<p>Read an integer, octal integer, or floating-point number.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readNumber</span><span class="hljs-params">(startsWithDot)</span> </span>{
|
||
<span class="hljs-keyword">var</span> start = tokPos, isFloat = <span class="hljs-literal">false</span>, octal = input.charCodeAt(tokPos) === <span class="hljs-number">48</span>;
|
||
<span class="hljs-keyword">if</span> (!startsWithDot && readInt(<span class="hljs-number">10</span>) === <span class="hljs-literal">null</span>) raise(start, <span class="hljs-string">"Invalid number"</span>);
|
||
<span class="hljs-keyword">if</span> (input.charCodeAt(tokPos) === <span class="hljs-number">46</span>) {
|
||
++tokPos;
|
||
readInt(<span class="hljs-number">10</span>);
|
||
isFloat = <span class="hljs-literal">true</span>;
|
||
}
|
||
<span class="hljs-keyword">var</span> next = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">69</span> || next === <span class="hljs-number">101</span>) { <span class="hljs-comment">// 'eE'</span>
|
||
next = input.charCodeAt(++tokPos);
|
||
<span class="hljs-keyword">if</span> (next === <span class="hljs-number">43</span> || next === <span class="hljs-number">45</span>) ++tokPos; <span class="hljs-comment">// '+-'</span>
|
||
<span class="hljs-keyword">if</span> (readInt(<span class="hljs-number">10</span>) === <span class="hljs-literal">null</span>) raise(start, <span class="hljs-string">"Invalid number"</span>);
|
||
isFloat = <span class="hljs-literal">true</span>;
|
||
}
|
||
<span class="hljs-keyword">if</span> (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, <span class="hljs-string">"Identifier directly after number"</span>);
|
||
|
||
<span class="hljs-keyword">var</span> str = input.slice(start, tokPos), val;
|
||
<span class="hljs-keyword">if</span> (isFloat) val = <span class="hljs-built_in">parseFloat</span>(str);
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!octal || str.length === <span class="hljs-number">1</span>) val = <span class="hljs-built_in">parseInt</span>(str, <span class="hljs-number">10</span>);
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-regexp">/[89]/</span>.test(str) || strict) raise(start, <span class="hljs-string">"Invalid number"</span>);
|
||
<span class="hljs-keyword">else</span> val = <span class="hljs-built_in">parseInt</span>(str, <span class="hljs-number">8</span>);
|
||
<span class="hljs-keyword">return</span> finishToken(_num, val);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-85">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-85">¶</a>
|
||
</div>
|
||
<p>Read a string value, interpreting backslash-escapes.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readCodePoint</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos), code;
|
||
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">123</span>) {
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion < <span class="hljs-number">6</span>) unexpected();
|
||
++tokPos;
|
||
code = readHexChar(input.indexOf(<span class="hljs-string">'}'</span>, tokPos) - tokPos);
|
||
++tokPos;
|
||
<span class="hljs-keyword">if</span> (code > <span class="hljs-number">0x10FFFF</span>) unexpected();
|
||
} <span class="hljs-keyword">else</span> {
|
||
code = readHexChar(<span class="hljs-number">4</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-86">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-86">¶</a>
|
||
</div>
|
||
<p>UTF-16 Encoding</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (code <= <span class="hljs-number">0xFFFF</span>) {
|
||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(code);
|
||
}
|
||
<span class="hljs-keyword">var</span> cu1 = ((code - <span class="hljs-number">0x10000</span>) >> <span class="hljs-number">10</span>) + <span class="hljs-number">0xD800</span>;
|
||
<span class="hljs-keyword">var</span> cu2 = ((code - <span class="hljs-number">0x10000</span>) & <span class="hljs-number">1023</span>) + <span class="hljs-number">0xDC00</span>;
|
||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(cu1, cu2);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readString</span><span class="hljs-params">(quote)</span> </span>{
|
||
++tokPos;
|
||
<span class="hljs-keyword">var</span> out = <span class="hljs-string">""</span>;
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">if</span> (tokPos >= inputLen) raise(tokStart, <span class="hljs-string">"Unterminated string constant"</span>);
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (ch === quote) {
|
||
++tokPos;
|
||
<span class="hljs-keyword">return</span> finishToken(_string, out);
|
||
}
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">92</span>) { <span class="hljs-comment">// '\'</span>
|
||
out += readEscapedChar();
|
||
} <span class="hljs-keyword">else</span> {
|
||
++tokPos;
|
||
<span class="hljs-keyword">if</span> (newline.test(<span class="hljs-built_in">String</span>.fromCharCode(ch))) {
|
||
raise(tokStart, <span class="hljs-string">"Unterminated string constant"</span>);
|
||
}
|
||
out += <span class="hljs-built_in">String</span>.fromCharCode(ch); <span class="hljs-comment">// '\'</span>
|
||
}
|
||
}
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readTmplString</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> out = <span class="hljs-string">""</span>;
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">if</span> (tokPos >= inputLen) raise(tokStart, <span class="hljs-string">"Unterminated string constant"</span>);
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">96</span> || ch === <span class="hljs-number">36</span> && input.charCodeAt(tokPos + <span class="hljs-number">1</span>) === <span class="hljs-number">123</span>) <span class="hljs-comment">// '`', '${'</span>
|
||
<span class="hljs-keyword">return</span> finishToken(_string, out);
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">92</span>) { <span class="hljs-comment">// '\'</span>
|
||
out += readEscapedChar();
|
||
} <span class="hljs-keyword">else</span> {
|
||
++tokPos;
|
||
<span class="hljs-keyword">if</span> (newline.test(<span class="hljs-built_in">String</span>.fromCharCode(ch))) {
|
||
<span class="hljs-keyword">if</span> (ch === <span class="hljs-number">13</span> && input.charCodeAt(tokPos) === <span class="hljs-number">10</span>) {
|
||
++tokPos;
|
||
ch = <span class="hljs-number">10</span>;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
++tokCurLine;
|
||
tokLineStart = tokPos;
|
||
}
|
||
}
|
||
out += <span class="hljs-built_in">String</span>.fromCharCode(ch); <span class="hljs-comment">// '\'</span>
|
||
}
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-87">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-87">¶</a>
|
||
</div>
|
||
<p>Used to read escaped characters</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readEscapedChar</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(++tokPos);
|
||
<span class="hljs-keyword">var</span> octal = <span class="hljs-regexp">/^[0-7]+/</span>.exec(input.slice(tokPos, tokPos + <span class="hljs-number">3</span>));
|
||
<span class="hljs-keyword">if</span> (octal) octal = octal[<span class="hljs-number">0</span>];
|
||
<span class="hljs-keyword">while</span> (octal && <span class="hljs-built_in">parseInt</span>(octal, <span class="hljs-number">8</span>) > <span class="hljs-number">255</span>) octal = octal.slice(<span class="hljs-number">0</span>, -<span class="hljs-number">1</span>);
|
||
<span class="hljs-keyword">if</span> (octal === <span class="hljs-string">"0"</span>) octal = <span class="hljs-literal">null</span>;
|
||
++tokPos;
|
||
<span class="hljs-keyword">if</span> (octal) {
|
||
<span class="hljs-keyword">if</span> (strict) raise(tokPos - <span class="hljs-number">2</span>, <span class="hljs-string">"Octal literal in strict mode"</span>);
|
||
tokPos += octal.length - <span class="hljs-number">1</span>;
|
||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(<span class="hljs-built_in">parseInt</span>(octal, <span class="hljs-number">8</span>));
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">switch</span> (ch) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">110</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\n"</span>; <span class="hljs-comment">// 'n' -> '\n'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">114</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\r"</span>; <span class="hljs-comment">// 'r' -> '\r'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">120</span>: <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(readHexChar(<span class="hljs-number">2</span>)); <span class="hljs-comment">// 'x'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">117</span>: <span class="hljs-keyword">return</span> readCodePoint(); <span class="hljs-comment">// 'u'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">85</span>: <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(readHexChar(<span class="hljs-number">8</span>)); <span class="hljs-comment">// 'U'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">116</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\t"</span>; <span class="hljs-comment">// 't' -> '\t'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">98</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\b"</span>; <span class="hljs-comment">// 'b' -> '\b'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">118</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\u000b"</span>; <span class="hljs-comment">// 'v' -> '\u000b'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">102</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\f"</span>; <span class="hljs-comment">// 'f' -> '\f'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">48</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"\0"</span>; <span class="hljs-comment">// 0 -> '\0'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">13</span>: <span class="hljs-keyword">if</span> (input.charCodeAt(tokPos) === <span class="hljs-number">10</span>) ++tokPos; <span class="hljs-comment">// '\r\n'</span>
|
||
<span class="hljs-keyword">case</span> <span class="hljs-number">10</span>: <span class="hljs-comment">// ' \n'</span>
|
||
<span class="hljs-keyword">if</span> (options.locations) { tokLineStart = tokPos; ++tokCurLine; }
|
||
<span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
|
||
<span class="hljs-keyword">default</span>: <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCharCode(ch);
|
||
}
|
||
}
|
||
}
|
||
|
||
<span class="hljs-keyword">var</span> XHTMLEntities = {
|
||
quot: <span class="hljs-string">'\u0022'</span>,
|
||
amp: <span class="hljs-string">'&'</span>,
|
||
apos: <span class="hljs-string">'\u0027'</span>,
|
||
lt: <span class="hljs-string">'<'</span>,
|
||
gt: <span class="hljs-string">'>'</span>,
|
||
nbsp: <span class="hljs-string">'\u00A0'</span>,
|
||
iexcl: <span class="hljs-string">'\u00A1'</span>,
|
||
cent: <span class="hljs-string">'\u00A2'</span>,
|
||
pound: <span class="hljs-string">'\u00A3'</span>,
|
||
curren: <span class="hljs-string">'\u00A4'</span>,
|
||
yen: <span class="hljs-string">'\u00A5'</span>,
|
||
brvbar: <span class="hljs-string">'\u00A6'</span>,
|
||
sect: <span class="hljs-string">'\u00A7'</span>,
|
||
uml: <span class="hljs-string">'\u00A8'</span>,
|
||
copy: <span class="hljs-string">'\u00A9'</span>,
|
||
ordf: <span class="hljs-string">'\u00AA'</span>,
|
||
laquo: <span class="hljs-string">'\u00AB'</span>,
|
||
not: <span class="hljs-string">'\u00AC'</span>,
|
||
shy: <span class="hljs-string">'\u00AD'</span>,
|
||
reg: <span class="hljs-string">'\u00AE'</span>,
|
||
macr: <span class="hljs-string">'\u00AF'</span>,
|
||
deg: <span class="hljs-string">'\u00B0'</span>,
|
||
plusmn: <span class="hljs-string">'\u00B1'</span>,
|
||
sup2: <span class="hljs-string">'\u00B2'</span>,
|
||
sup3: <span class="hljs-string">'\u00B3'</span>,
|
||
acute: <span class="hljs-string">'\u00B4'</span>,
|
||
micro: <span class="hljs-string">'\u00B5'</span>,
|
||
para: <span class="hljs-string">'\u00B6'</span>,
|
||
middot: <span class="hljs-string">'\u00B7'</span>,
|
||
cedil: <span class="hljs-string">'\u00B8'</span>,
|
||
sup1: <span class="hljs-string">'\u00B9'</span>,
|
||
ordm: <span class="hljs-string">'\u00BA'</span>,
|
||
raquo: <span class="hljs-string">'\u00BB'</span>,
|
||
frac14: <span class="hljs-string">'\u00BC'</span>,
|
||
frac12: <span class="hljs-string">'\u00BD'</span>,
|
||
frac34: <span class="hljs-string">'\u00BE'</span>,
|
||
iquest: <span class="hljs-string">'\u00BF'</span>,
|
||
Agrave: <span class="hljs-string">'\u00C0'</span>,
|
||
Aacute: <span class="hljs-string">'\u00C1'</span>,
|
||
Acirc: <span class="hljs-string">'\u00C2'</span>,
|
||
Atilde: <span class="hljs-string">'\u00C3'</span>,
|
||
Auml: <span class="hljs-string">'\u00C4'</span>,
|
||
Aring: <span class="hljs-string">'\u00C5'</span>,
|
||
AElig: <span class="hljs-string">'\u00C6'</span>,
|
||
Ccedil: <span class="hljs-string">'\u00C7'</span>,
|
||
Egrave: <span class="hljs-string">'\u00C8'</span>,
|
||
Eacute: <span class="hljs-string">'\u00C9'</span>,
|
||
Ecirc: <span class="hljs-string">'\u00CA'</span>,
|
||
Euml: <span class="hljs-string">'\u00CB'</span>,
|
||
Igrave: <span class="hljs-string">'\u00CC'</span>,
|
||
Iacute: <span class="hljs-string">'\u00CD'</span>,
|
||
Icirc: <span class="hljs-string">'\u00CE'</span>,
|
||
Iuml: <span class="hljs-string">'\u00CF'</span>,
|
||
ETH: <span class="hljs-string">'\u00D0'</span>,
|
||
Ntilde: <span class="hljs-string">'\u00D1'</span>,
|
||
Ograve: <span class="hljs-string">'\u00D2'</span>,
|
||
Oacute: <span class="hljs-string">'\u00D3'</span>,
|
||
Ocirc: <span class="hljs-string">'\u00D4'</span>,
|
||
Otilde: <span class="hljs-string">'\u00D5'</span>,
|
||
Ouml: <span class="hljs-string">'\u00D6'</span>,
|
||
times: <span class="hljs-string">'\u00D7'</span>,
|
||
Oslash: <span class="hljs-string">'\u00D8'</span>,
|
||
Ugrave: <span class="hljs-string">'\u00D9'</span>,
|
||
Uacute: <span class="hljs-string">'\u00DA'</span>,
|
||
Ucirc: <span class="hljs-string">'\u00DB'</span>,
|
||
Uuml: <span class="hljs-string">'\u00DC'</span>,
|
||
Yacute: <span class="hljs-string">'\u00DD'</span>,
|
||
THORN: <span class="hljs-string">'\u00DE'</span>,
|
||
szlig: <span class="hljs-string">'\u00DF'</span>,
|
||
agrave: <span class="hljs-string">'\u00E0'</span>,
|
||
aacute: <span class="hljs-string">'\u00E1'</span>,
|
||
acirc: <span class="hljs-string">'\u00E2'</span>,
|
||
atilde: <span class="hljs-string">'\u00E3'</span>,
|
||
auml: <span class="hljs-string">'\u00E4'</span>,
|
||
aring: <span class="hljs-string">'\u00E5'</span>,
|
||
aelig: <span class="hljs-string">'\u00E6'</span>,
|
||
ccedil: <span class="hljs-string">'\u00E7'</span>,
|
||
egrave: <span class="hljs-string">'\u00E8'</span>,
|
||
eacute: <span class="hljs-string">'\u00E9'</span>,
|
||
ecirc: <span class="hljs-string">'\u00EA'</span>,
|
||
euml: <span class="hljs-string">'\u00EB'</span>,
|
||
igrave: <span class="hljs-string">'\u00EC'</span>,
|
||
iacute: <span class="hljs-string">'\u00ED'</span>,
|
||
icirc: <span class="hljs-string">'\u00EE'</span>,
|
||
iuml: <span class="hljs-string">'\u00EF'</span>,
|
||
eth: <span class="hljs-string">'\u00F0'</span>,
|
||
ntilde: <span class="hljs-string">'\u00F1'</span>,
|
||
ograve: <span class="hljs-string">'\u00F2'</span>,
|
||
oacute: <span class="hljs-string">'\u00F3'</span>,
|
||
ocirc: <span class="hljs-string">'\u00F4'</span>,
|
||
otilde: <span class="hljs-string">'\u00F5'</span>,
|
||
ouml: <span class="hljs-string">'\u00F6'</span>,
|
||
divide: <span class="hljs-string">'\u00F7'</span>,
|
||
oslash: <span class="hljs-string">'\u00F8'</span>,
|
||
ugrave: <span class="hljs-string">'\u00F9'</span>,
|
||
uacute: <span class="hljs-string">'\u00FA'</span>,
|
||
ucirc: <span class="hljs-string">'\u00FB'</span>,
|
||
uuml: <span class="hljs-string">'\u00FC'</span>,
|
||
yacute: <span class="hljs-string">'\u00FD'</span>,
|
||
thorn: <span class="hljs-string">'\u00FE'</span>,
|
||
yuml: <span class="hljs-string">'\u00FF'</span>,
|
||
OElig: <span class="hljs-string">'\u0152'</span>,
|
||
oelig: <span class="hljs-string">'\u0153'</span>,
|
||
Scaron: <span class="hljs-string">'\u0160'</span>,
|
||
scaron: <span class="hljs-string">'\u0161'</span>,
|
||
Yuml: <span class="hljs-string">'\u0178'</span>,
|
||
fnof: <span class="hljs-string">'\u0192'</span>,
|
||
circ: <span class="hljs-string">'\u02C6'</span>,
|
||
tilde: <span class="hljs-string">'\u02DC'</span>,
|
||
Alpha: <span class="hljs-string">'\u0391'</span>,
|
||
Beta: <span class="hljs-string">'\u0392'</span>,
|
||
Gamma: <span class="hljs-string">'\u0393'</span>,
|
||
Delta: <span class="hljs-string">'\u0394'</span>,
|
||
Epsilon: <span class="hljs-string">'\u0395'</span>,
|
||
Zeta: <span class="hljs-string">'\u0396'</span>,
|
||
Eta: <span class="hljs-string">'\u0397'</span>,
|
||
Theta: <span class="hljs-string">'\u0398'</span>,
|
||
Iota: <span class="hljs-string">'\u0399'</span>,
|
||
Kappa: <span class="hljs-string">'\u039A'</span>,
|
||
Lambda: <span class="hljs-string">'\u039B'</span>,
|
||
Mu: <span class="hljs-string">'\u039C'</span>,
|
||
Nu: <span class="hljs-string">'\u039D'</span>,
|
||
Xi: <span class="hljs-string">'\u039E'</span>,
|
||
Omicron: <span class="hljs-string">'\u039F'</span>,
|
||
Pi: <span class="hljs-string">'\u03A0'</span>,
|
||
Rho: <span class="hljs-string">'\u03A1'</span>,
|
||
Sigma: <span class="hljs-string">'\u03A3'</span>,
|
||
Tau: <span class="hljs-string">'\u03A4'</span>,
|
||
Upsilon: <span class="hljs-string">'\u03A5'</span>,
|
||
Phi: <span class="hljs-string">'\u03A6'</span>,
|
||
Chi: <span class="hljs-string">'\u03A7'</span>,
|
||
Psi: <span class="hljs-string">'\u03A8'</span>,
|
||
Omega: <span class="hljs-string">'\u03A9'</span>,
|
||
alpha: <span class="hljs-string">'\u03B1'</span>,
|
||
beta: <span class="hljs-string">'\u03B2'</span>,
|
||
gamma: <span class="hljs-string">'\u03B3'</span>,
|
||
delta: <span class="hljs-string">'\u03B4'</span>,
|
||
epsilon: <span class="hljs-string">'\u03B5'</span>,
|
||
zeta: <span class="hljs-string">'\u03B6'</span>,
|
||
eta: <span class="hljs-string">'\u03B7'</span>,
|
||
theta: <span class="hljs-string">'\u03B8'</span>,
|
||
iota: <span class="hljs-string">'\u03B9'</span>,
|
||
kappa: <span class="hljs-string">'\u03BA'</span>,
|
||
lambda: <span class="hljs-string">'\u03BB'</span>,
|
||
mu: <span class="hljs-string">'\u03BC'</span>,
|
||
nu: <span class="hljs-string">'\u03BD'</span>,
|
||
xi: <span class="hljs-string">'\u03BE'</span>,
|
||
omicron: <span class="hljs-string">'\u03BF'</span>,
|
||
pi: <span class="hljs-string">'\u03C0'</span>,
|
||
rho: <span class="hljs-string">'\u03C1'</span>,
|
||
sigmaf: <span class="hljs-string">'\u03C2'</span>,
|
||
sigma: <span class="hljs-string">'\u03C3'</span>,
|
||
tau: <span class="hljs-string">'\u03C4'</span>,
|
||
upsilon: <span class="hljs-string">'\u03C5'</span>,
|
||
phi: <span class="hljs-string">'\u03C6'</span>,
|
||
chi: <span class="hljs-string">'\u03C7'</span>,
|
||
psi: <span class="hljs-string">'\u03C8'</span>,
|
||
omega: <span class="hljs-string">'\u03C9'</span>,
|
||
thetasym: <span class="hljs-string">'\u03D1'</span>,
|
||
upsih: <span class="hljs-string">'\u03D2'</span>,
|
||
piv: <span class="hljs-string">'\u03D6'</span>,
|
||
ensp: <span class="hljs-string">'\u2002'</span>,
|
||
emsp: <span class="hljs-string">'\u2003'</span>,
|
||
thinsp: <span class="hljs-string">'\u2009'</span>,
|
||
zwnj: <span class="hljs-string">'\u200C'</span>,
|
||
zwj: <span class="hljs-string">'\u200D'</span>,
|
||
lrm: <span class="hljs-string">'\u200E'</span>,
|
||
rlm: <span class="hljs-string">'\u200F'</span>,
|
||
ndash: <span class="hljs-string">'\u2013'</span>,
|
||
mdash: <span class="hljs-string">'\u2014'</span>,
|
||
lsquo: <span class="hljs-string">'\u2018'</span>,
|
||
rsquo: <span class="hljs-string">'\u2019'</span>,
|
||
sbquo: <span class="hljs-string">'\u201A'</span>,
|
||
ldquo: <span class="hljs-string">'\u201C'</span>,
|
||
rdquo: <span class="hljs-string">'\u201D'</span>,
|
||
bdquo: <span class="hljs-string">'\u201E'</span>,
|
||
dagger: <span class="hljs-string">'\u2020'</span>,
|
||
Dagger: <span class="hljs-string">'\u2021'</span>,
|
||
bull: <span class="hljs-string">'\u2022'</span>,
|
||
hellip: <span class="hljs-string">'\u2026'</span>,
|
||
permil: <span class="hljs-string">'\u2030'</span>,
|
||
prime: <span class="hljs-string">'\u2032'</span>,
|
||
Prime: <span class="hljs-string">'\u2033'</span>,
|
||
lsaquo: <span class="hljs-string">'\u2039'</span>,
|
||
rsaquo: <span class="hljs-string">'\u203A'</span>,
|
||
oline: <span class="hljs-string">'\u203E'</span>,
|
||
frasl: <span class="hljs-string">'\u2044'</span>,
|
||
euro: <span class="hljs-string">'\u20AC'</span>,
|
||
image: <span class="hljs-string">'\u2111'</span>,
|
||
weierp: <span class="hljs-string">'\u2118'</span>,
|
||
real: <span class="hljs-string">'\u211C'</span>,
|
||
trade: <span class="hljs-string">'\u2122'</span>,
|
||
alefsym: <span class="hljs-string">'\u2135'</span>,
|
||
larr: <span class="hljs-string">'\u2190'</span>,
|
||
uarr: <span class="hljs-string">'\u2191'</span>,
|
||
rarr: <span class="hljs-string">'\u2192'</span>,
|
||
darr: <span class="hljs-string">'\u2193'</span>,
|
||
harr: <span class="hljs-string">'\u2194'</span>,
|
||
crarr: <span class="hljs-string">'\u21B5'</span>,
|
||
lArr: <span class="hljs-string">'\u21D0'</span>,
|
||
uArr: <span class="hljs-string">'\u21D1'</span>,
|
||
rArr: <span class="hljs-string">'\u21D2'</span>,
|
||
dArr: <span class="hljs-string">'\u21D3'</span>,
|
||
hArr: <span class="hljs-string">'\u21D4'</span>,
|
||
forall: <span class="hljs-string">'\u2200'</span>,
|
||
part: <span class="hljs-string">'\u2202'</span>,
|
||
exist: <span class="hljs-string">'\u2203'</span>,
|
||
empty: <span class="hljs-string">'\u2205'</span>,
|
||
nabla: <span class="hljs-string">'\u2207'</span>,
|
||
isin: <span class="hljs-string">'\u2208'</span>,
|
||
notin: <span class="hljs-string">'\u2209'</span>,
|
||
ni: <span class="hljs-string">'\u220B'</span>,
|
||
prod: <span class="hljs-string">'\u220F'</span>,
|
||
sum: <span class="hljs-string">'\u2211'</span>,
|
||
minus: <span class="hljs-string">'\u2212'</span>,
|
||
lowast: <span class="hljs-string">'\u2217'</span>,
|
||
radic: <span class="hljs-string">'\u221A'</span>,
|
||
prop: <span class="hljs-string">'\u221D'</span>,
|
||
infin: <span class="hljs-string">'\u221E'</span>,
|
||
ang: <span class="hljs-string">'\u2220'</span>,
|
||
and: <span class="hljs-string">'\u2227'</span>,
|
||
or: <span class="hljs-string">'\u2228'</span>,
|
||
cap: <span class="hljs-string">'\u2229'</span>,
|
||
cup: <span class="hljs-string">'\u222A'</span>,
|
||
<span class="hljs-string">'int'</span>: <span class="hljs-string">'\u222B'</span>,
|
||
there4: <span class="hljs-string">'\u2234'</span>,
|
||
sim: <span class="hljs-string">'\u223C'</span>,
|
||
cong: <span class="hljs-string">'\u2245'</span>,
|
||
asymp: <span class="hljs-string">'\u2248'</span>,
|
||
ne: <span class="hljs-string">'\u2260'</span>,
|
||
equiv: <span class="hljs-string">'\u2261'</span>,
|
||
le: <span class="hljs-string">'\u2264'</span>,
|
||
ge: <span class="hljs-string">'\u2265'</span>,
|
||
sub: <span class="hljs-string">'\u2282'</span>,
|
||
sup: <span class="hljs-string">'\u2283'</span>,
|
||
nsub: <span class="hljs-string">'\u2284'</span>,
|
||
sube: <span class="hljs-string">'\u2286'</span>,
|
||
supe: <span class="hljs-string">'\u2287'</span>,
|
||
oplus: <span class="hljs-string">'\u2295'</span>,
|
||
otimes: <span class="hljs-string">'\u2297'</span>,
|
||
perp: <span class="hljs-string">'\u22A5'</span>,
|
||
sdot: <span class="hljs-string">'\u22C5'</span>,
|
||
lceil: <span class="hljs-string">'\u2308'</span>,
|
||
rceil: <span class="hljs-string">'\u2309'</span>,
|
||
lfloor: <span class="hljs-string">'\u230A'</span>,
|
||
rfloor: <span class="hljs-string">'\u230B'</span>,
|
||
lang: <span class="hljs-string">'\u2329'</span>,
|
||
rang: <span class="hljs-string">'\u232A'</span>,
|
||
loz: <span class="hljs-string">'\u25CA'</span>,
|
||
spades: <span class="hljs-string">'\u2660'</span>,
|
||
clubs: <span class="hljs-string">'\u2663'</span>,
|
||
hearts: <span class="hljs-string">'\u2665'</span>,
|
||
diams: <span class="hljs-string">'\u2666'</span>
|
||
};
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readXJSEntity</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> str = <span class="hljs-string">''</span>, count = <span class="hljs-number">0</span>, entity;
|
||
<span class="hljs-keyword">var</span> ch = nextChar();
|
||
<span class="hljs-keyword">if</span> (ch !== <span class="hljs-string">'&'</span>) raise(tokPos, <span class="hljs-string">"Entity must start with an ampersand"</span>);
|
||
tokPos++;
|
||
<span class="hljs-keyword">while</span> (tokPos < inputLen && count++ <span class="xml"><span class="hljs-tag">< <span class="hljs-attribute">10</span>) {
|
||
<span class="hljs-attribute">ch</span> = <span class="hljs-attribute">nextChar</span>();
|
||
<span class="hljs-attribute">tokPos</span>++;
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">ch</span> =<span class="hljs-value">==</span> ';') {
|
||
<span class="hljs-attribute">break</span>;
|
||
}
|
||
<span class="hljs-attribute">str</span> += <span class="hljs-attribute">ch</span>;
|
||
}
|
||
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">str</span>[<span class="hljs-attribute">0</span>] =<span class="hljs-value">==</span> '#' && <span class="hljs-attribute">str</span>[<span class="hljs-attribute">1</span>] =<span class="hljs-value">==</span> '<span class="hljs-attribute">x</span>') {
|
||
<span class="hljs-attribute">entity</span> = <span class="hljs-attribute">String.fromCharCode</span>(<span class="hljs-attribute">parseInt</span>(<span class="hljs-attribute">str.substr</span>(<span class="hljs-attribute">2</span>), <span class="hljs-attribute">16</span>));
|
||
} <span class="hljs-attribute">else</span> <span class="hljs-attribute">if</span> (<span class="hljs-attribute">str</span>[<span class="hljs-attribute">0</span>] =<span class="hljs-value">==</span> '#') {
|
||
<span class="hljs-attribute">entity</span> = <span class="hljs-attribute">String.fromCharCode</span>(<span class="hljs-attribute">parseInt</span>(<span class="hljs-attribute">str.substr</span>(<span class="hljs-attribute">1</span>), <span class="hljs-attribute">10</span>));
|
||
} <span class="hljs-attribute">else</span> {
|
||
<span class="hljs-attribute">entity</span> = <span class="hljs-attribute">XHTMLEntities</span>[<span class="hljs-attribute">str</span>];
|
||
}
|
||
<span class="hljs-attribute">return</span> <span class="hljs-attribute">entity</span>;
|
||
}
|
||
|
||
<span class="hljs-attribute">function</span> <span class="hljs-attribute">readXJSText</span>(<span class="hljs-attribute">stopChars</span>) {
|
||
<span class="hljs-attribute">var</span> <span class="hljs-attribute">str</span> = '';
|
||
<span class="hljs-attribute">while</span> (<span class="hljs-attribute">tokPos</span> < <span class="hljs-attribute">inputLen</span>) {
|
||
<span class="hljs-attribute">var</span> <span class="hljs-attribute">ch</span> = <span class="hljs-attribute">nextChar</span>();
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">stopChars.indexOf</span>(<span class="hljs-attribute">ch</span>) !=<span class="hljs-value">=</span> <span class="hljs-attribute">-1</span>) {
|
||
<span class="hljs-attribute">break</span>;
|
||
}
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">ch</span> =<span class="hljs-value">==</span> '&') {
|
||
<span class="hljs-attribute">str</span> += <span class="hljs-attribute">readXJSEntity</span>();
|
||
} <span class="hljs-attribute">else</span> {
|
||
++<span class="hljs-attribute">tokPos</span>;
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">ch</span> =<span class="hljs-value">==</span> '\<span class="hljs-attribute">r</span>' && <span class="hljs-attribute">nextChar</span>() =<span class="hljs-value">==</span> '\<span class="hljs-attribute">n</span>') {
|
||
<span class="hljs-attribute">str</span> += <span class="hljs-attribute">ch</span>;
|
||
++<span class="hljs-attribute">tokPos</span>;
|
||
<span class="hljs-attribute">ch</span> = '\<span class="hljs-attribute">n</span>';
|
||
}
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">ch</span> =<span class="hljs-value">==</span> '\<span class="hljs-attribute">n</span>' && <span class="hljs-attribute">options.locations</span>) {
|
||
<span class="hljs-attribute">tokLineStart</span> = <span class="hljs-attribute">tokPos</span>;
|
||
++<span class="hljs-attribute">tokCurLine</span>;
|
||
}
|
||
<span class="hljs-attribute">str</span> += <span class="hljs-attribute">ch</span>;
|
||
}
|
||
}
|
||
<span class="hljs-attribute">return</span> <span class="hljs-attribute">finishToken</span>(<span class="hljs-attribute">_xjsText</span>, <span class="hljs-attribute">str</span>);
|
||
}
|
||
|
||
<span class="hljs-attribute">function</span> <span class="hljs-attribute">readXJSStringLiteral</span>() {
|
||
<span class="hljs-attribute">var</span> <span class="hljs-attribute">quote</span> = <span class="hljs-attribute">input.charCodeAt</span>(<span class="hljs-attribute">tokPos</span>);
|
||
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">quote</span> !=<span class="hljs-value">=</span> <span class="hljs-attribute">34</span> && <span class="hljs-attribute">quote</span> !=<span class="hljs-value">=</span> <span class="hljs-attribute">39</span>) {
|
||
<span class="hljs-attribute">raise</span>("<span class="hljs-attribute">String</span> <span class="hljs-attribute">literal</span> <span class="hljs-attribute">must</span> <span class="hljs-attribute">starts</span> <span class="hljs-attribute">with</span> <span class="hljs-attribute">a</span> <span class="hljs-attribute">quote</span>");
|
||
}
|
||
|
||
++<span class="hljs-attribute">tokPos</span>;
|
||
|
||
<span class="hljs-attribute">readXJSText</span>([<span class="hljs-attribute">String.fromCharCode</span>(<span class="hljs-attribute">quote</span>)]);
|
||
|
||
<span class="hljs-attribute">if</span> (<span class="hljs-attribute">quote</span> !=<span class="hljs-value">=</span> <span class="hljs-attribute">input.charCodeAt</span>(<span class="hljs-attribute">tokPos</span>)) {
|
||
<span class="hljs-attribute">unexpected</span>();
|
||
}
|
||
|
||
++<span class="hljs-attribute">tokPos</span>;
|
||
|
||
<span class="hljs-attribute">return</span> <span class="hljs-attribute">finishToken</span>(<span class="hljs-attribute">tokType</span>, <span class="hljs-attribute">tokVal</span>);
|
||
}
|
||
|
||
</span></span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-88">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-88">¶</a>
|
||
</div>
|
||
<p>Used to read character escape sequences (‘\x’, ‘\u’, ‘\U’).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readHexChar</span><span class="hljs-params">(len)</span> </span>{
|
||
<span class="hljs-keyword">var</span> n = readInt(<span class="hljs-number">16</span>, len);
|
||
<span class="hljs-keyword">if</span> (n === <span class="hljs-literal">null</span>) raise(tokStart, <span class="hljs-string">"Bad character escape sequence"</span>);
|
||
<span class="hljs-keyword">return</span> n;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-89">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-89">¶</a>
|
||
</div>
|
||
<p>Used to signal to callers of <code>readWord1</code> whether the word
|
||
contained any escape sequences. This is needed because words with
|
||
escape sequences must not be interpreted as keywords.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">var</span> containsEsc;</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-90">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-90">¶</a>
|
||
</div>
|
||
<p>Read an identifier, and return it as a string. Sets <code>containsEsc</code>
|
||
to whether the word contained a ‘\u’ escape.</p>
|
||
<p>Only builds up the word character-by-character when it actually
|
||
containeds an escape, as a micro-optimization.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readWord1</span><span class="hljs-params">()</span> </span>{
|
||
containsEsc = <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">var</span> word, first = <span class="hljs-literal">true</span>, start = tokPos;
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">var</span> ch = input.charCodeAt(tokPos);
|
||
<span class="hljs-keyword">if</span> (isIdentifierChar(ch) || (inXJSTag && ch === <span class="hljs-number">45</span>)) {
|
||
<span class="hljs-keyword">if</span> (containsEsc) word += nextChar();
|
||
++tokPos;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ch === <span class="hljs-number">92</span> && !inXJSTag) { <span class="hljs-comment">// "\"</span>
|
||
<span class="hljs-keyword">if</span> (!containsEsc) word = input.slice(start, tokPos);
|
||
containsEsc = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (input.charCodeAt(++tokPos) != <span class="hljs-number">117</span>) <span class="hljs-comment">// "u"</span>
|
||
raise(tokPos, <span class="hljs-string">"Expecting Unicode escape sequence \\uXXXX"</span>);
|
||
++tokPos;
|
||
<span class="hljs-keyword">var</span> esc = readHexChar(<span class="hljs-number">4</span>);
|
||
<span class="hljs-keyword">var</span> escStr = <span class="hljs-built_in">String</span>.fromCharCode(esc);
|
||
<span class="hljs-keyword">if</span> (!escStr) raise(tokPos - <span class="hljs-number">1</span>, <span class="hljs-string">"Invalid Unicode escape"</span>);
|
||
<span class="hljs-keyword">if</span> (!(first ? isIdentifierStart(esc) : isIdentifierChar(esc)))
|
||
raise(tokPos - <span class="hljs-number">4</span>, <span class="hljs-string">"Invalid Unicode escape"</span>);
|
||
word += escStr;
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
first = <span class="hljs-literal">false</span>;
|
||
}
|
||
<span class="hljs-keyword">return</span> containsEsc ? word : input.slice(start, tokPos);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-91">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-91">¶</a>
|
||
</div>
|
||
<p>Read an identifier or keyword token. Will check for reserved
|
||
words when necessary.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readWord</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> word = readWord1();
|
||
<span class="hljs-keyword">var</span> type = inXJSTag ? _xjsName : _name;
|
||
<span class="hljs-keyword">if</span> (!containsEsc && isKeyword(word))
|
||
type = keywordTypes[word];
|
||
<span class="hljs-keyword">return</span> finishToken(type, word);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-92">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-92">¶</a>
|
||
</div>
|
||
<h2 id="parser">Parser</h2>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-93">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-93">¶</a>
|
||
</div>
|
||
<p>A recursive descent parser operates by defining functions for all
|
||
syntactic elements, and recursively calling those, each function
|
||
advancing the input stream and returning an AST node. Precedence
|
||
of constructs (for example, the fact that <code>!x[1]</code> means <code>!(x[1])</code>
|
||
instead of <code>(!x)[1]</code> is handled by the fact that the parser
|
||
function that parses unary prefix operators is called first, and
|
||
in turn calls the function that parses <code>[]</code> subscripts — that
|
||
way, it’ll receive the node for <code>x[1]</code> already parsed, and wraps
|
||
<em>that</em> in the unary operator node.</p>
|
||
<p>Acorn uses an <a href="http://en.wikipedia.org/wiki/Operator-precedence_parser">operator precedence parser</a> to handle binary
|
||
operator precedence, because it is much more compact than using
|
||
the technique outlined above, which uses different, nesting
|
||
functions to specify precedence, for all of the ten binary
|
||
precedence levels that JavaScript defines.</p>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-94">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-94">¶</a>
|
||
</div>
|
||
<h3 id="parser-utilities">Parser utilities</h3>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-95">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-95">¶</a>
|
||
</div>
|
||
<p>Continue to the next token.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">next</span><span class="hljs-params">()</span> </span>{
|
||
lastStart = tokStart;
|
||
lastEnd = tokEnd;
|
||
lastEndLoc = tokEndLoc;
|
||
readToken();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-96">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-96">¶</a>
|
||
</div>
|
||
<p>Enter strict mode. Re-reads the next token to please pedantic
|
||
tests (“use strict”; 010; — should fail).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setStrict</span><span class="hljs-params">(strct)</span> </span>{
|
||
strict = strct;
|
||
tokPos = tokStart;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
<span class="hljs-keyword">while</span> (tokPos < tokLineStart) {
|
||
tokLineStart = input.lastIndexOf(<span class="hljs-string">"\n"</span>, tokLineStart - <span class="hljs-number">2</span>) + <span class="hljs-number">1</span>;
|
||
--tokCurLine;
|
||
}
|
||
}
|
||
skipSpace();
|
||
readToken();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-97">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-97">¶</a>
|
||
</div>
|
||
<p>Start an AST node, attaching a start offset.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Node</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">this</span>.type = <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">this</span>.start = tokStart;
|
||
<span class="hljs-keyword">this</span>.end = <span class="hljs-literal">null</span>;
|
||
}
|
||
|
||
exports.Node = Node;
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SourceLocation</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">this</span>.start = tokStartLoc;
|
||
<span class="hljs-keyword">this</span>.end = <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">if</span> (sourceFile !== <span class="hljs-literal">null</span>) <span class="hljs-keyword">this</span>.source = sourceFile;
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startNode</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = <span class="hljs-keyword">new</span> Node();
|
||
<span class="hljs-keyword">if</span> (options.locations)
|
||
node.loc = <span class="hljs-keyword">new</span> SourceLocation();
|
||
<span class="hljs-keyword">if</span> (options.directSourceFile)
|
||
node.sourceFile = options.directSourceFile;
|
||
<span class="hljs-keyword">if</span> (options.ranges)
|
||
node.range = [tokStart, <span class="hljs-number">0</span>];
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-98">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-98">¶</a>
|
||
</div>
|
||
<p>Start a node whose start offset information should be based on
|
||
the start of another node. For example, a binary operator node is
|
||
only started after its left-hand side has already been parsed.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startNodeFrom</span><span class="hljs-params">(other)</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = <span class="hljs-keyword">new</span> Node();
|
||
node.start = other.start;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
node.loc = <span class="hljs-keyword">new</span> SourceLocation();
|
||
node.loc.start = other.loc.start;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.ranges)
|
||
node.range = [other.range[<span class="hljs-number">0</span>], <span class="hljs-number">0</span>];
|
||
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-99">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-99">¶</a>
|
||
</div>
|
||
<p>Finish an AST node, adding <code>type</code> and <code>end</code> properties.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finishNode</span><span class="hljs-params">(node, type)</span> </span>{
|
||
node.type = type;
|
||
node.end = lastEnd;
|
||
<span class="hljs-keyword">if</span> (options.locations)
|
||
node.loc.end = lastEndLoc;
|
||
<span class="hljs-keyword">if</span> (options.ranges)
|
||
node.range[<span class="hljs-number">1</span>] = lastEnd;
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-100">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-100">¶</a>
|
||
</div>
|
||
<p>Test whether a statement node is the string literal <code>"use strict"</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isUseStrict</span><span class="hljs-params">(stmt)</span> </span>{
|
||
<span class="hljs-keyword">return</span> options.ecmaVersion >= <span class="hljs-number">5</span> && stmt.type === <span class="hljs-string">"ExpressionStatement"</span> &&
|
||
stmt.expression.type === <span class="hljs-string">"Literal"</span> && stmt.expression.value === <span class="hljs-string">"use strict"</span>;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-101">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-101">¶</a>
|
||
</div>
|
||
<p>Predicate that tests whether the next token is of the given
|
||
type, and if yes, consumes it as a side effect.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">eat</span><span class="hljs-params">(type)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (tokType === type) {
|
||
next();
|
||
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-102">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-102">¶</a>
|
||
</div>
|
||
<p>Test whether a semicolon can be inserted at the current position.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">canInsertSemicolon</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">return</span> !options.strictSemicolons &&
|
||
(tokType === _eof || tokType === _braceR || newline.test(input.slice(lastEnd, tokStart)));
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-103">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-103">¶</a>
|
||
</div>
|
||
<p>Consume a semicolon, or, failing that, see if we are allowed to
|
||
pretend that there is a semicolon at this position.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">semicolon</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (!eat(_semi) && !canInsertSemicolon()) unexpected();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-104">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-104">¶</a>
|
||
</div>
|
||
<p>Expect a token of a given type. If found, consume it, otherwise,
|
||
raise an unexpected token error.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">expect</span><span class="hljs-params">(type)</span> </span>{
|
||
eat(type) || unexpected();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-105">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-105">¶</a>
|
||
</div>
|
||
<p>Get following char.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nextChar</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">return</span> input.charAt(tokPos);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-106">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-106">¶</a>
|
||
</div>
|
||
<p>Raise an unexpected token error.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unexpected</span><span class="hljs-params">(pos)</span> </span>{
|
||
raise(pos != <span class="hljs-literal">null</span> ? pos : tokStart, <span class="hljs-string">"Unexpected token"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-107">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-107">¶</a>
|
||
</div>
|
||
<p>Checks if hash object has a property.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">has</span><span class="hljs-params">(obj, propName)</span> </span>{
|
||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.prototype.hasOwnProperty.call(obj, propName);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-108">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-108">¶</a>
|
||
</div>
|
||
<p>Convert existing expression atom to assignable pattern
|
||
if possible.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toAssignable</span><span class="hljs-params">(node, allowSpread, checkType)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && node) {
|
||
<span class="hljs-keyword">switch</span> (node.type) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"Identifier"</span>:
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"MemberExpression"</span>:
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ObjectExpression"</span>:
|
||
node.type = <span class="hljs-string">"ObjectPattern"</span>;
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < node.properties.length; i++) {
|
||
<span class="hljs-keyword">var</span> prop = node.properties[i];
|
||
<span class="hljs-keyword">if</span> (prop.kind !== <span class="hljs-string">"init"</span>) unexpected(prop.key.start);
|
||
toAssignable(prop.value, <span class="hljs-literal">false</span>, checkType);
|
||
}
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ArrayExpression"</span>:
|
||
node.type = <span class="hljs-string">"ArrayPattern"</span>;
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, lastI = node.elements.length - <span class="hljs-number">1</span>; i <= lastI; i++) {
|
||
toAssignable(node.elements[i], i === lastI, checkType);
|
||
}
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"SpreadElement"</span>:
|
||
<span class="hljs-keyword">if</span> (allowSpread) {
|
||
toAssignable(node.argument, <span class="hljs-literal">false</span>, checkType);
|
||
checkSpreadAssign(node.argument);
|
||
} <span class="hljs-keyword">else</span> {
|
||
unexpected(node.start);
|
||
}
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
<span class="hljs-keyword">if</span> (checkType) unexpected(node.start);
|
||
}
|
||
}
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-109">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-109">¶</a>
|
||
</div>
|
||
<p>Checks if node can be assignable spread argument.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkSpreadAssign</span><span class="hljs-params">(node)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (node.type !== <span class="hljs-string">"Identifier"</span> && node.type !== <span class="hljs-string">"ArrayPattern"</span>)
|
||
unexpected(node.start);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-110">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-110">¶</a>
|
||
</div>
|
||
<p>Verify that argument names are not repeated, and it does not
|
||
try to bind the words <code>eval</code> or <code>arguments</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkFunctionParam</span><span class="hljs-params">(param, nameHash)</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (param.type) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"Identifier"</span>:
|
||
<span class="hljs-keyword">if</span> (isStrictReservedWord(param.name) || isStrictBadIdWord(param.name))
|
||
raise(param.start, <span class="hljs-string">"Defining '"</span> + param.name + <span class="hljs-string">"' in strict mode"</span>);
|
||
<span class="hljs-keyword">if</span> (has(nameHash, param.name))
|
||
raise(param.start, <span class="hljs-string">"Argument name clash in strict mode"</span>);
|
||
nameHash[param.name] = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ObjectPattern"</span>:
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < param.properties.length; i++)
|
||
checkFunctionParam(param.properties[i].value, nameHash);
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ArrayPattern"</span>:
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < param.elements.length; i++)
|
||
checkFunctionParam(param.elements[i], nameHash);
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-111">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-111">¶</a>
|
||
</div>
|
||
<p>Check if property name clashes with already added.
|
||
Object/class getters and setters are not allowed to clash —
|
||
either with each other or with an init property — and in
|
||
strict mode, init properties are also not allowed to be repeated.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkPropClash</span><span class="hljs-params">(prop, propHash)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (prop.computed) <span class="hljs-keyword">return</span>;
|
||
<span class="hljs-keyword">var</span> key = prop.key, name;
|
||
<span class="hljs-keyword">switch</span> (key.type) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"Identifier"</span>: name = key.name; <span class="hljs-keyword">break</span>;
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"Literal"</span>: name = <span class="hljs-built_in">String</span>(key.value); <span class="hljs-keyword">break</span>;
|
||
<span class="hljs-keyword">default</span>: <span class="hljs-keyword">return</span>;
|
||
}
|
||
<span class="hljs-keyword">var</span> kind = prop.kind || <span class="hljs-string">"init"</span>, other;
|
||
<span class="hljs-keyword">if</span> (has(propHash, name)) {
|
||
other = propHash[name];
|
||
<span class="hljs-keyword">var</span> isGetSet = kind !== <span class="hljs-string">"init"</span>;
|
||
<span class="hljs-keyword">if</span> ((strict || isGetSet) && other[kind] || !(isGetSet ^ other.init))
|
||
raise(key.start, <span class="hljs-string">"Redefinition of property"</span>);
|
||
} <span class="hljs-keyword">else</span> {
|
||
other = propHash[name] = {
|
||
init: <span class="hljs-literal">false</span>,
|
||
get: <span class="hljs-literal">false</span>,
|
||
set: <span class="hljs-literal">false</span>
|
||
};
|
||
}
|
||
other[kind] = <span class="hljs-literal">true</span>;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-112">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-112">¶</a>
|
||
</div>
|
||
<p>Verify that a node is an lval — something that can be assigned
|
||
to.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkLVal</span><span class="hljs-params">(expr, isBinding)</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (expr.type) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"Identifier"</span>:
|
||
<span class="hljs-keyword">if</span> (strict && (isStrictBadIdWord(expr.name) || isStrictReservedWord(expr.name)))
|
||
raise(expr.start, isBinding
|
||
? <span class="hljs-string">"Binding "</span> + expr.name + <span class="hljs-string">" in strict mode"</span>
|
||
: <span class="hljs-string">"Assigning to "</span> + expr.name + <span class="hljs-string">" in strict mode"</span>
|
||
);
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"MemberExpression"</span>:
|
||
<span class="hljs-keyword">if</span> (!isBinding) <span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ObjectPattern"</span>:
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < expr.properties.length; i++)
|
||
checkLVal(expr.properties[i].value, isBinding);
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"ArrayPattern"</span>:
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < expr.elements.length; i++) {
|
||
<span class="hljs-keyword">var</span> elem = expr.elements[i];
|
||
<span class="hljs-keyword">if</span> (elem) checkLVal(elem, isBinding);
|
||
}
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">"SpreadElement"</span>:
|
||
<span class="hljs-keyword">break</span>;
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
raise(expr.start, <span class="hljs-string">"Assigning to rvalue"</span>);
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-113">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-113">¶</a>
|
||
</div>
|
||
<h3 id="statement-parsing">Statement parsing</h3>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-114">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-114">¶</a>
|
||
</div>
|
||
<p>Parse a program. Initializes the parser, reads any number of
|
||
statements, and wraps them in a Program node. Optionally takes a
|
||
<code>program</code> argument. If present, the statements will be appended
|
||
to its body instead of creating a new node.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseTopLevel</span><span class="hljs-params">(program)</span> </span>{
|
||
lastStart = lastEnd = tokPos;
|
||
<span class="hljs-keyword">if</span> (options.locations) lastEndLoc = <span class="hljs-keyword">new</span> Position;
|
||
inFunction = inGenerator = strict = <span class="hljs-literal">null</span>;
|
||
labels = [];
|
||
readToken();
|
||
|
||
<span class="hljs-keyword">var</span> node = program || startNode(), first = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (!program) node.body = [];
|
||
<span class="hljs-keyword">while</span> (tokType !== _eof) {
|
||
<span class="hljs-keyword">var</span> stmt = parseStatement();
|
||
node.body.push(stmt);
|
||
<span class="hljs-keyword">if</span> (first && isUseStrict(stmt)) setStrict(<span class="hljs-literal">true</span>);
|
||
first = <span class="hljs-literal">false</span>;
|
||
}
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"Program"</span>);
|
||
}
|
||
|
||
<span class="hljs-keyword">var</span> loopLabel = {kind: <span class="hljs-string">"loop"</span>}, switchLabel = {kind: <span class="hljs-string">"switch"</span>};</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-115">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-115">¶</a>
|
||
</div>
|
||
<p>Parse a single statement.</p>
|
||
<p>If expecting a statement and finding a slash operator, parse a
|
||
regular expression literal. This is to handle cases like
|
||
<code>if (foo) /blah/.exec(foo);</code>, where looking at the previous token
|
||
does not help.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseStatement</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (tokType === _slash || tokType === _assign && tokVal == <span class="hljs-string">"/="</span>)
|
||
readToken(<span class="hljs-literal">true</span>);
|
||
|
||
<span class="hljs-keyword">var</span> starttype = tokType, node = startNode();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-116">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-116">¶</a>
|
||
</div>
|
||
<p>Most types of statements are recognized by the keyword they
|
||
start with. Many are trivial to parse, some require a bit of
|
||
complexity.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">switch</span> (starttype) {
|
||
<span class="hljs-keyword">case</span> _break: <span class="hljs-keyword">case</span> _continue: <span class="hljs-keyword">return</span> parseBreakContinueStatement(node, starttype.keyword);
|
||
<span class="hljs-keyword">case</span> _debugger: <span class="hljs-keyword">return</span> parseDebuggerStatement(node);
|
||
<span class="hljs-keyword">case</span> _do: <span class="hljs-keyword">return</span> parseDoStatement(node);
|
||
<span class="hljs-keyword">case</span> _for: <span class="hljs-keyword">return</span> parseForStatement(node);
|
||
<span class="hljs-keyword">case</span> _function: <span class="hljs-keyword">return</span> parseFunctionStatement(node);
|
||
<span class="hljs-keyword">case</span> _class: <span class="hljs-keyword">return</span> parseClass(node, <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">case</span> _if: <span class="hljs-keyword">return</span> parseIfStatement(node);
|
||
<span class="hljs-keyword">case</span> _return: <span class="hljs-keyword">return</span> parseReturnStatement(node);
|
||
<span class="hljs-keyword">case</span> _switch: <span class="hljs-keyword">return</span> parseSwitchStatement(node);
|
||
<span class="hljs-keyword">case</span> _throw: <span class="hljs-keyword">return</span> parseThrowStatement(node);
|
||
<span class="hljs-keyword">case</span> _try: <span class="hljs-keyword">return</span> parseTryStatement(node);
|
||
<span class="hljs-keyword">case</span> _var: <span class="hljs-keyword">case</span> _let: <span class="hljs-keyword">case</span> _const: <span class="hljs-keyword">return</span> parseVarStatement(node, starttype.keyword);
|
||
<span class="hljs-keyword">case</span> _while: <span class="hljs-keyword">return</span> parseWhileStatement(node);
|
||
<span class="hljs-keyword">case</span> _with: <span class="hljs-keyword">return</span> parseWithStatement(node);
|
||
<span class="hljs-keyword">case</span> _braceL: <span class="hljs-keyword">return</span> parseBlock(); <span class="hljs-comment">// no point creating a function for this</span>
|
||
<span class="hljs-keyword">case</span> _semi: <span class="hljs-keyword">return</span> parseEmptyStatement(node);
|
||
<span class="hljs-keyword">case</span> _export: <span class="hljs-keyword">return</span> parseExport(node);
|
||
<span class="hljs-keyword">case</span> _import: <span class="hljs-keyword">return</span> parseImport(node);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-117">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-117">¶</a>
|
||
</div>
|
||
<p>If the statement does not start with a statement keyword or a
|
||
brace, it’s an ExpressionStatement or LabeledStatement. We
|
||
simply start parsing an expression, and afterwards, if the
|
||
next token is a colon and the expression was a simple
|
||
Identifier node, we switch to interpreting it as a label.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">default</span>:
|
||
<span class="hljs-keyword">var</span> maybeName = tokVal, expr = parseExpression();
|
||
<span class="hljs-keyword">if</span> (starttype === _name && expr.type === <span class="hljs-string">"Identifier"</span> && eat(_colon))
|
||
<span class="hljs-keyword">return</span> parseLabeledStatement(node, maybeName, expr);
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> parseExpressionStatement(node, expr);
|
||
}
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseBreakContinueStatement</span><span class="hljs-params">(node, keyword)</span> </span>{
|
||
<span class="hljs-keyword">var</span> isBreak = keyword == <span class="hljs-string">"break"</span>;
|
||
next();
|
||
<span class="hljs-keyword">if</span> (eat(_semi) || canInsertSemicolon()) node.label = <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tokType !== _name) unexpected();
|
||
<span class="hljs-keyword">else</span> {
|
||
node.label = parseIdent();
|
||
semicolon();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-118">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-118">¶</a>
|
||
</div>
|
||
<p>Verify that there is an actual destination to break or
|
||
continue to.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < labels.length; ++i) {
|
||
<span class="hljs-keyword">var</span> lab = labels[i];
|
||
<span class="hljs-keyword">if</span> (node.label == <span class="hljs-literal">null</span> || lab.name === node.label.name) {
|
||
<span class="hljs-keyword">if</span> (lab.kind != <span class="hljs-literal">null</span> && (isBreak || lab.kind === <span class="hljs-string">"loop"</span>)) <span class="hljs-keyword">break</span>;
|
||
<span class="hljs-keyword">if</span> (node.label && isBreak) <span class="hljs-keyword">break</span>;
|
||
}
|
||
}
|
||
<span class="hljs-keyword">if</span> (i === labels.length) raise(node.start, <span class="hljs-string">"Unsyntactic "</span> + keyword);
|
||
<span class="hljs-keyword">return</span> finishNode(node, isBreak ? <span class="hljs-string">"BreakStatement"</span> : <span class="hljs-string">"ContinueStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseDebuggerStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
semicolon();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"DebuggerStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseDoStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
labels.push(loopLabel);
|
||
node.body = parseStatement();
|
||
labels.pop();
|
||
expect(_while);
|
||
node.test = parseParenExpression();
|
||
semicolon();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"DoWhileStatement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-119">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-119">¶</a>
|
||
</div>
|
||
<p>Disambiguating between a <code>for</code> and a <code>for</code>/<code>in</code> or <code>for</code>/<code>of</code>
|
||
loop is non-trivial. Basically, we have to parse the init <code>var</code>
|
||
statement or expression, disallowing the <code>in</code> operator (see
|
||
the second parameter to <code>parseExpression</code>), and then check
|
||
whether the next token is <code>in</code> or <code>of</code>. When there is no init
|
||
part (semicolon immediately after the opening parenthesis), it
|
||
is a regular <code>for</code> loop.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseForStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
labels.push(loopLabel);
|
||
expect(_parenL);
|
||
<span class="hljs-keyword">if</span> (tokType === _semi) <span class="hljs-keyword">return</span> parseFor(node, <span class="hljs-literal">null</span>);
|
||
<span class="hljs-keyword">if</span> (tokType === _var || tokType === _let) {
|
||
<span class="hljs-keyword">var</span> init = startNode(), varKind = tokType.keyword, isLet = tokType === _let;
|
||
next();
|
||
parseVar(init, <span class="hljs-literal">true</span>, varKind);
|
||
finishNode(init, <span class="hljs-string">"VariableDeclaration"</span>);
|
||
<span class="hljs-keyword">if</span> ((tokType === _in || (tokType === _name && tokVal === <span class="hljs-string">"of"</span>)) && init.declarations.length === <span class="hljs-number">1</span> &&
|
||
!(isLet && init.declarations[<span class="hljs-number">0</span>].init))
|
||
<span class="hljs-keyword">return</span> parseForIn(node, init);
|
||
<span class="hljs-keyword">return</span> parseFor(node, init);
|
||
}
|
||
<span class="hljs-keyword">var</span> init = parseExpression(<span class="hljs-literal">false</span>, <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">if</span> (tokType === _in || (tokType === _name && tokVal === <span class="hljs-string">"of"</span>)) {
|
||
checkLVal(init);
|
||
<span class="hljs-keyword">return</span> parseForIn(node, init);
|
||
}
|
||
<span class="hljs-keyword">return</span> parseFor(node, init);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseFunctionStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
<span class="hljs-keyword">return</span> parseFunction(node, <span class="hljs-literal">true</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseIfStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
node.test = parseParenExpression();
|
||
node.consequent = parseStatement();
|
||
node.alternate = eat(_else) ? parseStatement() : <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"IfStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseReturnStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (!inFunction && !options.allowReturnOutsideFunction)
|
||
raise(tokStart, <span class="hljs-string">"'return' outside of function"</span>);
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-120">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-120">¶</a>
|
||
</div>
|
||
<p>In <code>return</code> (and <code>break</code>/<code>continue</code>), the keywords with
|
||
optional arguments, we eagerly look for a semicolon or the
|
||
possibility to insert one.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">if</span> (eat(_semi) || canInsertSemicolon()) node.argument = <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">else</span> { node.argument = parseExpression(); semicolon(); }
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ReturnStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseSwitchStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
node.discriminant = parseParenExpression();
|
||
node.cases = [];
|
||
expect(_braceL);
|
||
labels.push(switchLabel);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-121">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-121">¶</a>
|
||
</div>
|
||
<p>Statements under must be grouped (by label) in SwitchCase
|
||
nodes. <code>cur</code> is used to keep the node that we are currently
|
||
adding statements to.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> cur, sawDefault; tokType != _braceR;) {
|
||
<span class="hljs-keyword">if</span> (tokType === _case || tokType === _default) {
|
||
<span class="hljs-keyword">var</span> isCase = tokType === _case;
|
||
<span class="hljs-keyword">if</span> (cur) finishNode(cur, <span class="hljs-string">"SwitchCase"</span>);
|
||
node.cases.push(cur = startNode());
|
||
cur.consequent = [];
|
||
next();
|
||
<span class="hljs-keyword">if</span> (isCase) cur.test = parseExpression();
|
||
<span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">if</span> (sawDefault) raise(lastStart, <span class="hljs-string">"Multiple default clauses"</span>); sawDefault = <span class="hljs-literal">true</span>;
|
||
cur.test = <span class="hljs-literal">null</span>;
|
||
}
|
||
expect(_colon);
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">if</span> (!cur) unexpected();
|
||
cur.consequent.push(parseStatement());
|
||
}
|
||
}
|
||
<span class="hljs-keyword">if</span> (cur) finishNode(cur, <span class="hljs-string">"SwitchCase"</span>);
|
||
next(); <span class="hljs-comment">// Closing brace</span>
|
||
labels.pop();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"SwitchStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseThrowStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
<span class="hljs-keyword">if</span> (newline.test(input.slice(lastEnd, tokStart)))
|
||
raise(lastEnd, <span class="hljs-string">"Illegal newline after throw"</span>);
|
||
node.argument = parseExpression();
|
||
semicolon();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ThrowStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseTryStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
node.block = parseBlock();
|
||
node.handler = <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">if</span> (tokType === _catch) {
|
||
<span class="hljs-keyword">var</span> clause = startNode();
|
||
next();
|
||
expect(_parenL);
|
||
clause.param = parseIdent();
|
||
<span class="hljs-keyword">if</span> (strict && isStrictBadIdWord(clause.param.name))
|
||
raise(clause.param.start, <span class="hljs-string">"Binding "</span> + clause.param.name + <span class="hljs-string">" in strict mode"</span>);
|
||
expect(_parenR);
|
||
clause.guard = <span class="hljs-literal">null</span>;
|
||
clause.body = parseBlock();
|
||
node.handler = finishNode(clause, <span class="hljs-string">"CatchClause"</span>);
|
||
}
|
||
node.guardedHandlers = empty;
|
||
node.finalizer = eat(_finally) ? parseBlock() : <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">if</span> (!node.handler && !node.finalizer)
|
||
raise(node.start, <span class="hljs-string">"Missing catch or finally clause"</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"TryStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseVarStatement</span><span class="hljs-params">(node, kind)</span> </span>{
|
||
next();
|
||
parseVar(node, <span class="hljs-literal">false</span>, kind);
|
||
semicolon();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"VariableDeclaration"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseWhileStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
node.test = parseParenExpression();
|
||
labels.push(loopLabel);
|
||
node.body = parseStatement();
|
||
labels.pop();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"WhileStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseWithStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (strict) raise(tokStart, <span class="hljs-string">"'with' in strict mode"</span>);
|
||
next();
|
||
node.object = parseParenExpression();
|
||
node.body = parseStatement();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"WithStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseEmptyStatement</span><span class="hljs-params">(node)</span> </span>{
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"EmptyStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseLabeledStatement</span><span class="hljs-params">(node, maybeName, expr)</span> </span>{
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < labels.length; ++i)
|
||
<span class="hljs-keyword">if</span> (labels[i].name === maybeName) raise(expr.start, <span class="hljs-string">"Label '"</span> + maybeName + <span class="hljs-string">"' is already declared"</span>);
|
||
<span class="hljs-keyword">var</span> kind = tokType.isLoop ? <span class="hljs-string">"loop"</span> : tokType === _switch ? <span class="hljs-string">"switch"</span> : <span class="hljs-literal">null</span>;
|
||
labels.push({name: maybeName, kind: kind});
|
||
node.body = parseStatement();
|
||
labels.pop();
|
||
node.label = expr;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"LabeledStatement"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExpressionStatement</span><span class="hljs-params">(node, expr)</span> </span>{
|
||
node.expression = expr;
|
||
semicolon();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ExpressionStatement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-122">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-122">¶</a>
|
||
</div>
|
||
<p>Used for constructs like <code>switch</code> and <code>if</code> that insist on
|
||
parentheses around their expression.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseParenExpression</span><span class="hljs-params">()</span> </span>{
|
||
expect(_parenL);
|
||
<span class="hljs-keyword">var</span> val = parseExpression();
|
||
expect(_parenR);
|
||
<span class="hljs-keyword">return</span> val;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-123">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-123">¶</a>
|
||
</div>
|
||
<p>Parse a semicolon-enclosed block of statements, handling <code>"use
|
||
strict"</code> declarations when <code>allowStrict</code> is true (used for
|
||
function bodies).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseBlock</span><span class="hljs-params">(allowStrict)</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode(), first = <span class="hljs-literal">true</span>, strict = <span class="hljs-literal">false</span>, oldStrict;
|
||
node.body = [];
|
||
expect(_braceL);
|
||
<span class="hljs-keyword">while</span> (!eat(_braceR)) {
|
||
<span class="hljs-keyword">var</span> stmt = parseStatement();
|
||
node.body.push(stmt);
|
||
<span class="hljs-keyword">if</span> (first && allowStrict && isUseStrict(stmt)) {
|
||
oldStrict = strict;
|
||
setStrict(strict = <span class="hljs-literal">true</span>);
|
||
}
|
||
first = <span class="hljs-literal">false</span>;
|
||
}
|
||
<span class="hljs-keyword">if</span> (strict && !oldStrict) setStrict(<span class="hljs-literal">false</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"BlockStatement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-124">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-124">¶</a>
|
||
</div>
|
||
<p>Parse a regular <code>for</code> loop. The disambiguation code in
|
||
<code>parseStatement</code> will already have parsed the init statement or
|
||
expression.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseFor</span><span class="hljs-params">(node, init)</span> </span>{
|
||
node.init = init;
|
||
expect(_semi);
|
||
node.test = tokType === _semi ? <span class="hljs-literal">null</span> : parseExpression();
|
||
expect(_semi);
|
||
node.update = tokType === _parenR ? <span class="hljs-literal">null</span> : parseExpression();
|
||
expect(_parenR);
|
||
node.body = parseStatement();
|
||
labels.pop();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ForStatement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-125">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-125">¶</a>
|
||
</div>
|
||
<p>Parse a <code>for</code>/<code>in</code> and <code>for</code>/<code>of</code> loop, which are almost
|
||
same from parser’s perspective.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseForIn</span><span class="hljs-params">(node, init)</span> </span>{
|
||
<span class="hljs-keyword">var</span> type = tokType === _in ? <span class="hljs-string">"ForInStatement"</span> : <span class="hljs-string">"ForOfStatement"</span>;
|
||
next();
|
||
node.left = init;
|
||
node.right = parseExpression();
|
||
expect(_parenR);
|
||
node.body = parseStatement();
|
||
labels.pop();
|
||
<span class="hljs-keyword">return</span> finishNode(node, type);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-126">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-126">¶</a>
|
||
</div>
|
||
<p>Parse a list of variable declarations.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseVar</span><span class="hljs-params">(node, noIn, kind)</span> </span>{
|
||
node.declarations = [];
|
||
node.kind = kind;
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">var</span> decl = startNode();
|
||
decl.id = options.ecmaVersion >= <span class="hljs-number">6</span> ? toAssignable(parseExprAtom()) : parseIdent();
|
||
checkLVal(decl.id, <span class="hljs-literal">true</span>);
|
||
decl.init = eat(_eq) ? parseExpression(<span class="hljs-literal">true</span>, noIn) : (kind === _const.keyword ? unexpected() : <span class="hljs-literal">null</span>);
|
||
node.declarations.push(finishNode(decl, <span class="hljs-string">"VariableDeclarator"</span>));
|
||
<span class="hljs-keyword">if</span> (!eat(_comma)) <span class="hljs-keyword">break</span>;
|
||
}
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-127">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-127">¶</a>
|
||
</div>
|
||
<h3 id="expression-parsing">Expression parsing</h3>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-128">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-128">¶</a>
|
||
</div>
|
||
<p>These nest, from the most general expression type at the top to
|
||
‘atomic’, nondivisible expression types at the bottom. Most of
|
||
the functions will simply let the function(s) below them parse,
|
||
and, <em>if</em> the syntactic construct they handle is present, wrap
|
||
the AST node that the inner parser gave them in another node.</p>
|
||
|
||
</div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-129">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-129">¶</a>
|
||
</div>
|
||
<p>Parse a full expression. The arguments are used to forbid comma
|
||
sequences (in argument lists, array literals, or object literals)
|
||
or the <code>in</code> operator (in for loops initalization expressions).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExpression</span><span class="hljs-params">(noComma, noIn)</span> </span>{
|
||
<span class="hljs-keyword">var</span> expr = parseMaybeAssign(noIn);
|
||
<span class="hljs-keyword">if</span> (!noComma && tokType === _comma) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(expr);
|
||
node.expressions = [expr];
|
||
<span class="hljs-keyword">while</span> (eat(_comma)) node.expressions.push(parseMaybeAssign(noIn));
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"SequenceExpression"</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> expr;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-130">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-130">¶</a>
|
||
</div>
|
||
<p>Parse an assignment expression. This includes applications of
|
||
operators like <code>+=</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseMaybeAssign</span><span class="hljs-params">(noIn)</span> </span>{
|
||
<span class="hljs-keyword">var</span> left = parseMaybeConditional(noIn);
|
||
<span class="hljs-keyword">if</span> (tokType.isAssign) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(left);
|
||
node.operator = tokVal;
|
||
node.left = tokType === _eq ? toAssignable(left) : left;
|
||
checkLVal(left);
|
||
next();
|
||
node.right = parseMaybeAssign(noIn);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"AssignmentExpression"</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> left;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-131">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-131">¶</a>
|
||
</div>
|
||
<p>Parse a ternary conditional (<code>?:</code>) operator.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseMaybeConditional</span><span class="hljs-params">(noIn)</span> </span>{
|
||
<span class="hljs-keyword">var</span> expr = parseExprOps(noIn);
|
||
<span class="hljs-keyword">if</span> (eat(_question)) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(expr);
|
||
node.test = expr;
|
||
node.consequent = parseExpression(<span class="hljs-literal">true</span>);
|
||
expect(_colon);
|
||
node.alternate = parseExpression(<span class="hljs-literal">true</span>, noIn);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ConditionalExpression"</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> expr;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-132">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-132">¶</a>
|
||
</div>
|
||
<p>Start the precedence parser.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExprOps</span><span class="hljs-params">(noIn)</span> </span>{
|
||
<span class="hljs-keyword">return</span> parseExprOp(parseMaybeUnary(), -<span class="hljs-number">1</span>, noIn);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-133">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-133">¶</a>
|
||
</div>
|
||
<p>Parse binary operators with the operator precedence parsing
|
||
algorithm. <code>left</code> is the left-hand side of the operator.
|
||
<code>minPrec</code> provides context that allows the function to stop and
|
||
defer further parser to one of its callers when it encounters an
|
||
operator that has a lower precedence than the set it is parsing.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExprOp</span><span class="hljs-params">(left, minPrec, noIn)</span> </span>{
|
||
<span class="hljs-keyword">var</span> prec = tokType.binop;
|
||
<span class="hljs-keyword">if</span> (prec != <span class="hljs-literal">null</span> && (!noIn || tokType !== _in)) {
|
||
<span class="hljs-keyword">if</span> (prec > minPrec) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(left);
|
||
node.left = left;
|
||
node.operator = tokVal;
|
||
<span class="hljs-keyword">var</span> op = tokType;
|
||
next();
|
||
node.right = parseExprOp(parseMaybeUnary(), prec, noIn);
|
||
<span class="hljs-keyword">var</span> exprNode = finishNode(node, (op === _logicalOR || op === _logicalAND) ? <span class="hljs-string">"LogicalExpression"</span> : <span class="hljs-string">"BinaryExpression"</span>);
|
||
<span class="hljs-keyword">return</span> parseExprOp(exprNode, minPrec, noIn);
|
||
}
|
||
}
|
||
<span class="hljs-keyword">return</span> left;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-134">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-134">¶</a>
|
||
</div>
|
||
<p>Parse unary operators, both prefix and postfix.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseMaybeUnary</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (tokType.prefix) {
|
||
<span class="hljs-keyword">var</span> node = startNode(), update = tokType.isUpdate;
|
||
node.operator = tokVal;
|
||
node.prefix = <span class="hljs-literal">true</span>;
|
||
tokRegexpAllowed = <span class="hljs-literal">true</span>;
|
||
next();
|
||
node.argument = parseMaybeUnary();
|
||
<span class="hljs-keyword">if</span> (update) checkLVal(node.argument);
|
||
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (strict && node.operator === <span class="hljs-string">"delete"</span> &&
|
||
node.argument.type === <span class="hljs-string">"Identifier"</span>)
|
||
raise(node.start, <span class="hljs-string">"Deleting local variable in strict mode"</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, update ? <span class="hljs-string">"UpdateExpression"</span> : <span class="hljs-string">"UnaryExpression"</span>);
|
||
}
|
||
<span class="hljs-keyword">var</span> expr = parseExprSubscripts();
|
||
<span class="hljs-keyword">while</span> (tokType.postfix && !canInsertSemicolon()) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(expr);
|
||
node.operator = tokVal;
|
||
node.prefix = <span class="hljs-literal">false</span>;
|
||
node.argument = expr;
|
||
checkLVal(expr);
|
||
next();
|
||
expr = finishNode(node, <span class="hljs-string">"UpdateExpression"</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> expr;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-135">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-135">¶</a>
|
||
</div>
|
||
<p>Parse call, dot, and <code>[]</code>-subscript expressions.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExprSubscripts</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">return</span> parseSubscripts(parseExprAtom());
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseSubscripts</span><span class="hljs-params">(base, noCalls)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (eat(_dot)) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(base);
|
||
node.object = base;
|
||
node.property = parseIdent(<span class="hljs-literal">true</span>);
|
||
node.computed = <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">return</span> parseSubscripts(finishNode(node, <span class="hljs-string">"MemberExpression"</span>), noCalls);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (eat(_bracketL)) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(base);
|
||
node.object = base;
|
||
node.property = parseExpression();
|
||
node.computed = <span class="hljs-literal">true</span>;
|
||
expect(_bracketR);
|
||
<span class="hljs-keyword">return</span> parseSubscripts(finishNode(node, <span class="hljs-string">"MemberExpression"</span>), noCalls);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!noCalls && eat(_parenL)) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(base);
|
||
node.callee = base;
|
||
node.arguments = parseExprList(_parenR, <span class="hljs-literal">false</span>);
|
||
<span class="hljs-keyword">return</span> parseSubscripts(finishNode(node, <span class="hljs-string">"CallExpression"</span>), noCalls);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tokType === _bquote) {
|
||
<span class="hljs-keyword">var</span> node = startNodeFrom(base);
|
||
node.tag = base;
|
||
node.quasi = parseTemplate();
|
||
<span class="hljs-keyword">return</span> parseSubscripts(finishNode(node, <span class="hljs-string">"TaggedTemplateExpression"</span>), noCalls);
|
||
} <span class="hljs-keyword">return</span> base;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-136">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-136">¶</a>
|
||
</div>
|
||
<p>Parse an atomic expression — either a single token that is an
|
||
expression, an expression started by a keyword like <code>function</code> or
|
||
<code>new</code>, or an expression wrapped in punctuation like <code>()</code>, <code>[]</code>,
|
||
or <code>{}</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExprAtom</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (tokType) {
|
||
<span class="hljs-keyword">case</span> _this:
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ThisExpression"</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _yield:
|
||
<span class="hljs-keyword">if</span> (inGenerator) <span class="hljs-keyword">return</span> parseYield();
|
||
|
||
<span class="hljs-keyword">case</span> _name:
|
||
<span class="hljs-keyword">var</span> id = parseIdent(tokType !== _name);
|
||
<span class="hljs-keyword">if</span> (eat(_arrow)) {
|
||
<span class="hljs-keyword">return</span> parseArrowExpression(startNodeFrom(id), [id]);
|
||
}
|
||
<span class="hljs-keyword">return</span> id;
|
||
|
||
<span class="hljs-keyword">case</span> _num: <span class="hljs-keyword">case</span> _string: <span class="hljs-keyword">case</span> _regexp: <span class="hljs-keyword">case</span> _xjsText:
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.value = tokVal;
|
||
node.raw = input.slice(tokStart, tokEnd);
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"Literal"</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _null: <span class="hljs-keyword">case</span> _true: <span class="hljs-keyword">case</span> _false:
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.value = tokType.atomValue;
|
||
node.raw = tokType.keyword;
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"Literal"</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _parenL:
|
||
<span class="hljs-keyword">var</span> tokStartLoc1 = tokStartLoc, tokStart1 = tokStart, val, exprList;
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-137">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-137">¶</a>
|
||
</div>
|
||
<p>check whether this is generator comprehension or regular expression</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && tokType === _for) {
|
||
val = parseComprehension(startNode(), <span class="hljs-literal">true</span>);
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">var</span> oldParenL = ++metParenL;
|
||
<span class="hljs-keyword">if</span> (tokType !== _parenR) {
|
||
val = parseExpression();
|
||
exprList = val.type === <span class="hljs-string">"SequenceExpression"</span> ? val.expressions : [val];
|
||
} <span class="hljs-keyword">else</span> {
|
||
exprList = [];
|
||
}
|
||
expect(_parenR);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-138">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-138">¶</a>
|
||
</div>
|
||
<p>if ‘=>’ follows ‘(…)’, convert contents to arguments</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (metParenL === oldParenL && eat(_arrow)) {
|
||
val = parseArrowExpression(startNode(), exprList);
|
||
} <span class="hljs-keyword">else</span> {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-139">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-139">¶</a>
|
||
</div>
|
||
<p>forbid ‘()’ before everything but ‘=>’</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!val) unexpected(lastStart);</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-140">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-140">¶</a>
|
||
</div>
|
||
<p>forbid ‘…’ in sequence expressions</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < exprList.length; i++) {
|
||
<span class="hljs-keyword">if</span> (exprList[i].type === <span class="hljs-string">"SpreadElement"</span>) unexpected();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
val.start = tokStart1;
|
||
val.end = lastEnd;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
val.loc.start = tokStartLoc1;
|
||
val.loc.end = lastEndLoc;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.ranges) {
|
||
val.range = [tokStart1, lastEnd];
|
||
}
|
||
<span class="hljs-keyword">return</span> val;
|
||
|
||
<span class="hljs-keyword">case</span> _bracketL:
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-141">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-141">¶</a>
|
||
</div>
|
||
<p>check whether this is array comprehension or regular array</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && tokType === _for) {
|
||
<span class="hljs-keyword">return</span> parseComprehension(node, <span class="hljs-literal">false</span>);
|
||
}
|
||
node.elements = parseExprList(_bracketR, <span class="hljs-literal">true</span>, <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ArrayExpression"</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _braceL:
|
||
<span class="hljs-keyword">return</span> parseObj();
|
||
|
||
<span class="hljs-keyword">case</span> _function:
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
<span class="hljs-keyword">return</span> parseFunction(node, <span class="hljs-literal">false</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _class:
|
||
<span class="hljs-keyword">return</span> parseClass(startNode(), <span class="hljs-literal">false</span>);
|
||
|
||
<span class="hljs-keyword">case</span> _new:
|
||
<span class="hljs-keyword">return</span> parseNew();
|
||
|
||
<span class="hljs-keyword">case</span> _ellipsis:
|
||
<span class="hljs-keyword">return</span> parseSpread();
|
||
|
||
<span class="hljs-keyword">case</span> _bquote:
|
||
<span class="hljs-keyword">return</span> parseTemplate();
|
||
|
||
<span class="hljs-keyword">case</span> _lt:
|
||
<span class="hljs-keyword">return</span> parseXJSElement();
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
unexpected();
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-142">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-142">¶</a>
|
||
</div>
|
||
<p>New’s precedence is slightly tricky. It must allow its argument
|
||
to be a <code>[]</code> or dot subscript expression, but not a call — at
|
||
least, not without wrapping it in parentheses. Thus, it uses the</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseNew</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
node.callee = parseSubscripts(parseExprAtom(), <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">if</span> (eat(_parenL)) node.arguments = parseExprList(_parenR, <span class="hljs-literal">false</span>);
|
||
<span class="hljs-keyword">else</span> node.arguments = empty;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"NewExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-143">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-143">¶</a>
|
||
</div>
|
||
<p>Parse spread element ‘…expr’</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseSpread</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
node.argument = parseExpression(<span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"SpreadElement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-144">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-144">¶</a>
|
||
</div>
|
||
<p>Parse template expression.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseTemplate</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.expressions = [];
|
||
node.quasis = [];
|
||
inTemplate = <span class="hljs-literal">true</span>;
|
||
next();
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">var</span> elem = startNode();
|
||
elem.value = {cooked: tokVal, raw: input.slice(tokStart, tokEnd)};
|
||
elem.tail = <span class="hljs-literal">false</span>;
|
||
next();
|
||
node.quasis.push(finishNode(elem, <span class="hljs-string">"TemplateElement"</span>));
|
||
<span class="hljs-keyword">if</span> (eat(_bquote)) { <span class="hljs-comment">// '`', end of template</span>
|
||
elem.tail = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
inTemplate = <span class="hljs-literal">false</span>;
|
||
expect(_dollarBraceL);
|
||
node.expressions.push(parseExpression());
|
||
inTemplate = <span class="hljs-literal">true</span>;
|
||
expect(_braceR);
|
||
}
|
||
inTemplate = <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"TemplateLiteral"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-145">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-145">¶</a>
|
||
</div>
|
||
<p>Parse an object literal.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseObj</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode(), first = <span class="hljs-literal">true</span>, propHash = {};
|
||
node.properties = [];
|
||
next();
|
||
<span class="hljs-keyword">while</span> (!eat(_braceR)) {
|
||
<span class="hljs-keyword">if</span> (!first) {
|
||
expect(_comma);
|
||
<span class="hljs-keyword">if</span> (options.allowTrailingCommas && eat(_braceR)) <span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> first = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">var</span> prop = startNode(), isGenerator;
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
prop.method = <span class="hljs-literal">false</span>;
|
||
prop.shorthand = <span class="hljs-literal">false</span>;
|
||
isGenerator = eat(_star);
|
||
}
|
||
parsePropertyName(prop);
|
||
<span class="hljs-keyword">if</span> (eat(_colon)) {
|
||
prop.value = parseExpression(<span class="hljs-literal">true</span>);
|
||
prop.kind = <span class="hljs-string">"init"</span>;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && tokType === _parenL) {
|
||
prop.kind = <span class="hljs-string">"init"</span>;
|
||
prop.method = <span class="hljs-literal">true</span>;
|
||
prop.value = parseMethod(isGenerator);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">5</span> && !prop.computed && prop.key.type === <span class="hljs-string">"Identifier"</span> &&
|
||
(prop.key.name === <span class="hljs-string">"get"</span> || prop.key.name === <span class="hljs-string">"set"</span>)) {
|
||
<span class="hljs-keyword">if</span> (isGenerator) unexpected();
|
||
prop.kind = prop.key.name;
|
||
parsePropertyName(prop);
|
||
prop.value = parseMethod(<span class="hljs-literal">false</span>);
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && !prop.computed && prop.key.type === <span class="hljs-string">"Identifier"</span>) {
|
||
prop.kind = <span class="hljs-string">"init"</span>;
|
||
prop.value = prop.key;
|
||
prop.shorthand = <span class="hljs-literal">true</span>;
|
||
} <span class="hljs-keyword">else</span> unexpected();
|
||
|
||
checkPropClash(prop, propHash);
|
||
node.properties.push(finishNode(prop, <span class="hljs-string">"Property"</span>));
|
||
}
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ObjectExpression"</span>);
|
||
}
|
||
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parsePropertyName</span><span class="hljs-params">(prop)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
<span class="hljs-keyword">if</span> (eat(_bracketL)) {
|
||
prop.computed = <span class="hljs-literal">true</span>;
|
||
prop.key = parseExpression();
|
||
expect(_bracketR);
|
||
<span class="hljs-keyword">return</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
prop.computed = <span class="hljs-literal">false</span>;
|
||
}
|
||
}
|
||
prop.key = (tokType === _num || tokType === _string) ? parseExprAtom() : parseIdent(<span class="hljs-literal">true</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-146">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-146">¶</a>
|
||
</div>
|
||
<p>Initialize empty function node.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initFunction</span><span class="hljs-params">(node)</span> </span>{
|
||
node.id = <span class="hljs-literal">null</span>;
|
||
node.params = [];
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
node.defaults = [];
|
||
node.rest = <span class="hljs-literal">null</span>;
|
||
node.generator = <span class="hljs-literal">false</span>;
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-147">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-147">¶</a>
|
||
</div>
|
||
<p>Parse a function declaration or literal (depending on the
|
||
<code>isStatement</code> parameter).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseFunction</span><span class="hljs-params">(node, isStatement, allowExpressionBody)</span> </span>{
|
||
initFunction(node);
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
node.generator = eat(_star);
|
||
}
|
||
<span class="hljs-keyword">if</span> (isStatement || tokType === _name) {
|
||
node.id = parseIdent();
|
||
}
|
||
parseFunctionParams(node);
|
||
parseFunctionBody(node, allowExpressionBody);
|
||
<span class="hljs-keyword">return</span> finishNode(node, isStatement ? <span class="hljs-string">"FunctionDeclaration"</span> : <span class="hljs-string">"FunctionExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-148">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-148">¶</a>
|
||
</div>
|
||
<p>Parse object or class method.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseMethod</span><span class="hljs-params">(isGenerator)</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
initFunction(node);
|
||
parseFunctionParams(node);
|
||
<span class="hljs-keyword">var</span> allowExpressionBody;
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span>) {
|
||
node.generator = isGenerator;
|
||
allowExpressionBody = <span class="hljs-literal">true</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
allowExpressionBody = <span class="hljs-literal">false</span>;
|
||
}
|
||
parseFunctionBody(node, allowExpressionBody);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"FunctionExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-149">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-149">¶</a>
|
||
</div>
|
||
<p>Parse arrow function expression with given parameters.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseArrowExpression</span><span class="hljs-params">(node, params)</span> </span>{
|
||
initFunction(node);
|
||
|
||
<span class="hljs-keyword">var</span> defaults = node.defaults, hasDefaults = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, lastI = params.length - <span class="hljs-number">1</span>; i <= lastI; i++) {
|
||
<span class="hljs-keyword">var</span> param = params[i];
|
||
|
||
<span class="hljs-keyword">if</span> (param.type === <span class="hljs-string">"AssignmentExpression"</span> && param.operator === <span class="hljs-string">"="</span>) {
|
||
hasDefaults = <span class="hljs-literal">true</span>;
|
||
params[i] = param.left;
|
||
defaults.push(param.right);
|
||
} <span class="hljs-keyword">else</span> {
|
||
toAssignable(param, i === lastI, <span class="hljs-literal">true</span>);
|
||
defaults.push(<span class="hljs-literal">null</span>);
|
||
<span class="hljs-keyword">if</span> (param.type === <span class="hljs-string">"SpreadElement"</span>) {
|
||
params.length--;
|
||
node.rest = param.argument;
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
}
|
||
}
|
||
|
||
node.params = params;
|
||
<span class="hljs-keyword">if</span> (!hasDefaults) node.defaults = [];
|
||
|
||
parseFunctionBody(node, <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ArrowFunctionExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-150">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-150">¶</a>
|
||
</div>
|
||
<p>Parse function parameters.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseFunctionParams</span><span class="hljs-params">(node)</span> </span>{
|
||
<span class="hljs-keyword">var</span> defaults = [], hasDefaults = <span class="hljs-literal">false</span>;
|
||
|
||
expect(_parenL);
|
||
<span class="hljs-keyword">for</span> (;;) {
|
||
<span class="hljs-keyword">if</span> (eat(_parenR)) {
|
||
<span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && eat(_ellipsis)) {
|
||
node.rest = toAssignable(parseExprAtom(), <span class="hljs-literal">false</span>, <span class="hljs-literal">true</span>);
|
||
checkSpreadAssign(node.rest);
|
||
expect(_parenR);
|
||
<span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.params.push(options.ecmaVersion >= <span class="hljs-number">6</span> ? toAssignable(parseExprAtom(), <span class="hljs-literal">false</span>, <span class="hljs-literal">true</span>) : parseIdent());
|
||
<span class="hljs-keyword">if</span> (options.ecmaVersion >= <span class="hljs-number">6</span> && tokType === _eq) {
|
||
next();
|
||
hasDefaults = <span class="hljs-literal">true</span>;
|
||
defaults.push(parseExpression(<span class="hljs-literal">true</span>));
|
||
}
|
||
<span class="hljs-keyword">if</span> (!eat(_comma)) {
|
||
expect(_parenR);
|
||
<span class="hljs-keyword">break</span>;
|
||
}
|
||
}
|
||
}
|
||
|
||
<span class="hljs-keyword">if</span> (hasDefaults) node.defaults = defaults;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-151">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-151">¶</a>
|
||
</div>
|
||
<p>Parse function body and check parameters.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseFunctionBody</span><span class="hljs-params">(node, allowExpression)</span> </span>{
|
||
<span class="hljs-keyword">var</span> isExpression = allowExpression && tokType !== _braceL;
|
||
|
||
<span class="hljs-keyword">if</span> (isExpression) {
|
||
node.body = parseExpression(<span class="hljs-literal">true</span>);
|
||
node.expression = <span class="hljs-literal">true</span>;
|
||
} <span class="hljs-keyword">else</span> {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-152">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-152">¶</a>
|
||
</div>
|
||
<p>Start a new scope with regard to labels and the <code>inFunction</code>
|
||
flag (restore them to their old value afterwards).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> oldInFunc = inFunction, oldInGen = inGenerator, oldLabels = labels;
|
||
inFunction = <span class="hljs-literal">true</span>; inGenerator = node.generator; labels = [];
|
||
node.body = parseBlock(<span class="hljs-literal">true</span>);
|
||
node.expression = <span class="hljs-literal">false</span>;
|
||
inFunction = oldInFunc; inGenerator = oldInGen; labels = oldLabels;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-153">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-153">¶</a>
|
||
</div>
|
||
<p>If this is a strict mode function, verify that argument names
|
||
are not repeated, and it does not try to bind the words <code>eval</code>
|
||
or <code>arguments</code>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (strict || !isExpression && node.body.body.length && isUseStrict(node.body.body[<span class="hljs-number">0</span>])) {
|
||
<span class="hljs-keyword">var</span> nameHash = {};
|
||
<span class="hljs-keyword">if</span> (node.id)
|
||
checkFunctionParam(node.id, {});
|
||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < node.params.length; i++)
|
||
checkFunctionParam(node.params[i], nameHash);
|
||
<span class="hljs-keyword">if</span> (node.rest)
|
||
checkFunctionParam(node.rest, nameHash);
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-154">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-154">¶</a>
|
||
</div>
|
||
<p>Parse a class declaration or literal (depending on the
|
||
<code>isStatement</code> parameter).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseClass</span><span class="hljs-params">(node, isStatement)</span> </span>{
|
||
next();
|
||
node.id = tokType === _name ? parseIdent() : isStatement ? unexpected() : <span class="hljs-literal">null</span>;
|
||
node.superClass = eat(_extends) ? parseExpression() : <span class="hljs-literal">null</span>;
|
||
<span class="hljs-keyword">var</span> classBody = startNode(), methodHash = {}, staticMethodHash = {};
|
||
classBody.body = [];
|
||
expect(_braceL);
|
||
<span class="hljs-keyword">while</span> (!eat(_braceR)) {
|
||
<span class="hljs-keyword">var</span> method = startNode();
|
||
<span class="hljs-keyword">if</span> (tokType === _name && tokVal === <span class="hljs-string">"static"</span>) {
|
||
next();
|
||
method[<span class="hljs-string">'static'</span>] = <span class="hljs-literal">true</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
method[<span class="hljs-string">'static'</span>] = <span class="hljs-literal">false</span>;
|
||
}
|
||
<span class="hljs-keyword">var</span> isGenerator = eat(_star);
|
||
parsePropertyName(method);
|
||
<span class="hljs-keyword">if</span> (tokType === _name && !method.computed && method.key.type === <span class="hljs-string">"Identifier"</span> &&
|
||
(method.key.name === <span class="hljs-string">"get"</span> || method.key.name === <span class="hljs-string">"set"</span>)) {
|
||
<span class="hljs-keyword">if</span> (isGenerator) unexpected();
|
||
method.kind = method.key.name;
|
||
parsePropertyName(method);
|
||
} <span class="hljs-keyword">else</span> {
|
||
method.kind = <span class="hljs-string">""</span>;
|
||
}
|
||
method.value = parseMethod(isGenerator);
|
||
checkPropClash(method, method[<span class="hljs-string">'static'</span>] ? staticMethodHash : methodHash);
|
||
classBody.body.push(finishNode(method, <span class="hljs-string">"MethodDefinition"</span>));
|
||
eat(_semi);
|
||
}
|
||
node.body = finishNode(classBody, <span class="hljs-string">"ClassBody"</span>);
|
||
<span class="hljs-keyword">return</span> finishNode(node, isStatement ? <span class="hljs-string">"ClassDeclaration"</span> : <span class="hljs-string">"ClassExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-155">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-155">¶</a>
|
||
</div>
|
||
<p>Parses a comma-separated list of expressions, and returns them as
|
||
an array. <code>close</code> is the token type that ends the list, and
|
||
<code>allowEmpty</code> can be turned on to allow subsequent commas with
|
||
nothing in between them to be parsed as <code>null</code> (which is needed
|
||
for array literals).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExprList</span><span class="hljs-params">(close, allowTrailingComma, allowEmpty)</span> </span>{
|
||
<span class="hljs-keyword">var</span> elts = [], first = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">while</span> (!eat(close)) {
|
||
<span class="hljs-keyword">if</span> (!first) {
|
||
expect(_comma);
|
||
<span class="hljs-keyword">if</span> (allowTrailingComma && options.allowTrailingCommas && eat(close)) <span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> first = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">if</span> (allowEmpty && tokType === _comma) elts.push(<span class="hljs-literal">null</span>);
|
||
<span class="hljs-keyword">else</span> elts.push(parseExpression(<span class="hljs-literal">true</span>));
|
||
}
|
||
<span class="hljs-keyword">return</span> elts;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-156">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-156">¶</a>
|
||
</div>
|
||
<p>Parse the next token as an identifier. If <code>liberal</code> is true (used
|
||
when parsing properties), it will also convert keywords into
|
||
identifiers.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseIdent</span><span class="hljs-params">(liberal)</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
<span class="hljs-keyword">if</span> (liberal && options.forbidReserved == <span class="hljs-string">"everywhere"</span>) liberal = <span class="hljs-literal">false</span>;
|
||
<span class="hljs-keyword">if</span> (tokType === _name) {
|
||
<span class="hljs-keyword">if</span> (!liberal &&
|
||
(options.forbidReserved &&
|
||
(options.ecmaVersion === <span class="hljs-number">3</span> ? isReservedWord3 : isReservedWord5)(tokVal) ||
|
||
strict && isStrictReservedWord(tokVal)) &&
|
||
input.slice(tokStart, tokEnd).indexOf(<span class="hljs-string">"\\"</span>) == -<span class="hljs-number">1</span>)
|
||
raise(tokStart, <span class="hljs-string">"The keyword '"</span> + tokVal + <span class="hljs-string">"' is reserved"</span>);
|
||
node.name = tokVal;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (liberal && tokType.keyword) {
|
||
node.name = tokType.keyword;
|
||
} <span class="hljs-keyword">else</span> {
|
||
unexpected();
|
||
}
|
||
tokRegexpAllowed = <span class="hljs-literal">false</span>;
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"Identifier"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-157">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-157">¶</a>
|
||
</div>
|
||
<p>Parses module export declaration.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExport</span><span class="hljs-params">(node)</span> </span>{
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-158">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-158">¶</a>
|
||
</div>
|
||
<p>export var|const|let|function|class …;</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tokType === _var || tokType === _const || tokType === _let || tokType === _function || tokType === _class) {
|
||
node.declaration = parseStatement();
|
||
node[<span class="hljs-string">'default'</span>] = <span class="hljs-literal">false</span>;
|
||
node.specifiers = <span class="hljs-literal">null</span>;
|
||
node.source = <span class="hljs-literal">null</span>;
|
||
} <span class="hljs-keyword">else</span></pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-159">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-159">¶</a>
|
||
</div>
|
||
<p>export default …;</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (eat(_default)) {
|
||
node.declaration = parseExpression(<span class="hljs-literal">true</span>);
|
||
node[<span class="hljs-string">'default'</span>] = <span class="hljs-literal">true</span>;
|
||
node.specifiers = <span class="hljs-literal">null</span>;
|
||
node.source = <span class="hljs-literal">null</span>;
|
||
semicolon();
|
||
} <span class="hljs-keyword">else</span> {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-160">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-160">¶</a>
|
||
</div>
|
||
<p>export * from ‘…’
|
||
export { x, y as z } [from ‘…’]</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> isBatch = tokType === _star;
|
||
node.declaration = <span class="hljs-literal">null</span>;
|
||
node[<span class="hljs-string">'default'</span>] = <span class="hljs-literal">false</span>;
|
||
node.specifiers = parseExportSpecifiers();
|
||
<span class="hljs-keyword">if</span> (tokType === _name && tokVal === <span class="hljs-string">"from"</span>) {
|
||
next();
|
||
node.source = tokType === _string ? parseExprAtom() : unexpected();
|
||
} <span class="hljs-keyword">else</span> {
|
||
<span class="hljs-keyword">if</span> (isBatch) unexpected();
|
||
node.source = <span class="hljs-literal">null</span>;
|
||
}
|
||
}
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ExportDeclaration"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-161">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-161">¶</a>
|
||
</div>
|
||
<p>Parses a comma-separated list of module exports.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseExportSpecifiers</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> nodes = [], first = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (tokType === _star) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-162">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-162">¶</a>
|
||
</div>
|
||
<p>export * from ‘…’</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
nodes.push(finishNode(node, <span class="hljs-string">"ExportBatchSpecifier"</span>));
|
||
} <span class="hljs-keyword">else</span> {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-163">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-163">¶</a>
|
||
</div>
|
||
<p>export { x, y as z } [from ‘…’]</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> expect(_braceL);
|
||
<span class="hljs-keyword">while</span> (!eat(_braceR)) {
|
||
<span class="hljs-keyword">if</span> (!first) {
|
||
expect(_comma);
|
||
<span class="hljs-keyword">if</span> (options.allowTrailingCommas && eat(_braceR)) <span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> first = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.id = parseIdent();
|
||
<span class="hljs-keyword">if</span> (tokType === _name && tokVal === <span class="hljs-string">"as"</span>) {
|
||
next();
|
||
node.name = parseIdent(<span class="hljs-literal">true</span>);
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.name = <span class="hljs-literal">null</span>;
|
||
}
|
||
nodes.push(finishNode(node, <span class="hljs-string">"ExportSpecifier"</span>));
|
||
}
|
||
}
|
||
<span class="hljs-keyword">return</span> nodes;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-164">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-164">¶</a>
|
||
</div>
|
||
<p>Parses import declaration.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseImport</span><span class="hljs-params">(node)</span> </span>{
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-165">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-165">¶</a>
|
||
</div>
|
||
<p>import ‘…’;</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tokType === _string) {
|
||
node.specifiers = [];
|
||
node.source = parseExprAtom();
|
||
node.kind = <span class="hljs-string">""</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.specifiers = parseImportSpecifiers();
|
||
<span class="hljs-keyword">if</span> (tokType !== _name || tokVal !== <span class="hljs-string">"from"</span>) unexpected();
|
||
next();
|
||
node.source = tokType === _string ? parseExprAtom() : unexpected();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-166">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-166">¶</a>
|
||
</div>
|
||
<p>only for backward compatibility with Esprima’s AST
|
||
(it doesn’t support mixed default + named yet)</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> node.kind = node.specifiers[<span class="hljs-number">0</span>][<span class="hljs-string">'default'</span>] ? <span class="hljs-string">"default"</span> : <span class="hljs-string">"named"</span>;
|
||
}
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ImportDeclaration"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-167">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-167">¶</a>
|
||
</div>
|
||
<p>Parses a comma-separated list of module imports.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseImportSpecifiers</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> nodes = [], first = <span class="hljs-literal">true</span>;
|
||
<span class="hljs-keyword">if</span> (tokType === _star) {
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
<span class="hljs-keyword">if</span> (tokType !== _name || tokVal !== <span class="hljs-string">"as"</span>) unexpected();
|
||
next();
|
||
node.name = parseIdent();
|
||
checkLVal(node.name, <span class="hljs-literal">true</span>);
|
||
nodes.push(finishNode(node, <span class="hljs-string">"ImportBatchSpecifier"</span>));
|
||
<span class="hljs-keyword">return</span> nodes;
|
||
}
|
||
<span class="hljs-keyword">if</span> (tokType === _name) {</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-168">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-168">¶</a>
|
||
</div>
|
||
<p>import defaultObj, { x, y as z } from ‘…’</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> node = startNode();
|
||
node.id = parseIdent();
|
||
checkLVal(node.id, <span class="hljs-literal">true</span>);
|
||
node.name = <span class="hljs-literal">null</span>;
|
||
node[<span class="hljs-string">'default'</span>] = <span class="hljs-literal">true</span>;
|
||
nodes.push(finishNode(node, <span class="hljs-string">"ImportSpecifier"</span>));
|
||
<span class="hljs-keyword">if</span> (!eat(_comma)) <span class="hljs-keyword">return</span> nodes;
|
||
}
|
||
expect(_braceL);
|
||
<span class="hljs-keyword">while</span> (!eat(_braceR)) {
|
||
<span class="hljs-keyword">if</span> (!first) {
|
||
expect(_comma);
|
||
<span class="hljs-keyword">if</span> (options.allowTrailingCommas && eat(_braceR)) <span class="hljs-keyword">break</span>;
|
||
} <span class="hljs-keyword">else</span> first = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.id = parseIdent(<span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">if</span> (tokType === _name && tokVal === <span class="hljs-string">"as"</span>) {
|
||
next();
|
||
node.name = parseIdent();
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.name = <span class="hljs-literal">null</span>;
|
||
}
|
||
checkLVal(node.name || node.id, <span class="hljs-literal">true</span>);
|
||
node[<span class="hljs-string">'default'</span>] = <span class="hljs-literal">false</span>;
|
||
nodes.push(finishNode(node, <span class="hljs-string">"ImportSpecifier"</span>));
|
||
}
|
||
<span class="hljs-keyword">return</span> nodes;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-169">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-169">¶</a>
|
||
</div>
|
||
<p>Parses yield expression inside generator.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseYield</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
next();
|
||
<span class="hljs-keyword">if</span> (eat(_semi) || canInsertSemicolon()) {
|
||
node.delegate = <span class="hljs-literal">false</span>;
|
||
node.argument = <span class="hljs-literal">null</span>;
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.delegate = eat(_star);
|
||
node.argument = parseExpression(<span class="hljs-literal">true</span>);
|
||
}
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"YieldExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-170">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-170">¶</a>
|
||
</div>
|
||
<p>Parses array and generator comprehensions.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseComprehension</span><span class="hljs-params">(node, isGenerator)</span> </span>{
|
||
node.blocks = [];
|
||
<span class="hljs-keyword">while</span> (tokType === _for) {
|
||
<span class="hljs-keyword">var</span> block = startNode();
|
||
next();
|
||
expect(_parenL);
|
||
block.left = toAssignable(parseExprAtom());
|
||
checkLVal(block.left, <span class="hljs-literal">true</span>);
|
||
<span class="hljs-keyword">if</span> (tokType !== _name || tokVal !== <span class="hljs-string">"of"</span>) unexpected();
|
||
next();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-171">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-171">¶</a>
|
||
</div>
|
||
<p><code>of</code> property is here for compatibility with Esprima’s AST
|
||
which also supports deprecated [for (… in …) expr]</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> block.of = <span class="hljs-literal">true</span>;
|
||
block.right = parseExpression();
|
||
expect(_parenR);
|
||
node.blocks.push(finishNode(block, <span class="hljs-string">"ComprehensionBlock"</span>));
|
||
}
|
||
node.filter = eat(_if) ? parseParenExpression() : <span class="hljs-literal">null</span>;
|
||
node.body = parseExpression();
|
||
expect(isGenerator ? _parenR : _bracketR);
|
||
node.generator = isGenerator;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"ComprehensionExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-172">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-172">¶</a>
|
||
</div>
|
||
<p>Transforms JSX element name to string.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getQualifiedXJSName</span><span class="hljs-params">(object)</span> </span>{
|
||
<span class="hljs-keyword">if</span> (object.type === <span class="hljs-string">"XJSIdentifier"</span>) {
|
||
<span class="hljs-keyword">return</span> object.name;
|
||
}
|
||
<span class="hljs-keyword">if</span> (object.type === <span class="hljs-string">"XJSNamespacedName"</span>) {
|
||
<span class="hljs-keyword">return</span> object.namespace.name + <span class="hljs-string">':'</span> + object.name.name;
|
||
}
|
||
<span class="hljs-keyword">if</span> (object.type === <span class="hljs-string">"XJSMemberExpression"</span>) {
|
||
<span class="hljs-keyword">return</span> (
|
||
getQualifiedXJSName(object.object) + <span class="hljs-string">'.'</span> +
|
||
getQualifiedXJSName(object.property)
|
||
);
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-173">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-173">¶</a>
|
||
</div>
|
||
<p>Parse next token as JSX identifier</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSIdentifier</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
<span class="hljs-keyword">if</span> (tokType === _xjsName) {
|
||
node.name = tokVal;
|
||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tokType.keyword) {
|
||
node.name = tokType.keyword;
|
||
} <span class="hljs-keyword">else</span> {
|
||
unexpected();
|
||
}
|
||
tokRegexpAllowed = <span class="hljs-literal">false</span>;
|
||
next();
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSIdentifier"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-174">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-174">¶</a>
|
||
</div>
|
||
<p>Parse namespaced identifier.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSNamespacedName</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
|
||
node.namespace = parseXJSIdentifier();
|
||
expect(_colon);
|
||
node.name = parseXJSIdentifier();
|
||
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSNamespacedName"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-175">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-175">¶</a>
|
||
</div>
|
||
<p>Parse JSX object.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSMemberExpression</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = parseXJSIdentifier();
|
||
|
||
<span class="hljs-keyword">while</span> (eat(_dot)) {
|
||
<span class="hljs-keyword">var</span> newNode = startNodeFrom(node);
|
||
newNode.object = node;
|
||
newNode.property = parseXJSIdentifier();
|
||
node = finishNode(newNode, <span class="hljs-string">"XJSMemberExpression"</span>);
|
||
}
|
||
|
||
<span class="hljs-keyword">return</span> node;
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-176">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-176">¶</a>
|
||
</div>
|
||
<p>Parses element name in any form - namespaced, object
|
||
or single identifier.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSElementName</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (nextChar()) {
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">':'</span>:
|
||
<span class="hljs-keyword">return</span> parseXJSNamespacedName();
|
||
|
||
<span class="hljs-keyword">case</span> <span class="hljs-string">'.'</span>:
|
||
<span class="hljs-keyword">return</span> parseXJSMemberExpression();
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
<span class="hljs-keyword">return</span> parseXJSIdentifier();
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-177">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-177">¶</a>
|
||
</div>
|
||
<p>Parses attribute name as optionally namespaced identifier.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSAttributeName</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (nextChar() === <span class="hljs-string">':'</span>) {
|
||
<span class="hljs-keyword">return</span> parseXJSNamespacedName();
|
||
}
|
||
|
||
<span class="hljs-keyword">return</span> parseXJSIdentifier();
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-178">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-178">¶</a>
|
||
</div>
|
||
<p>Parses any type of JSX attribute value.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSAttributeValue</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (tokType) {
|
||
<span class="hljs-keyword">case</span> _braceL:
|
||
<span class="hljs-keyword">var</span> node = parseXJSExpressionContainer();
|
||
<span class="hljs-keyword">if</span> (node.expression.type === <span class="hljs-string">"XJSEmptyExpression"</span>) {
|
||
raise(
|
||
node.start,
|
||
<span class="hljs-string">'XJS attributes must only be assigned a non-empty '</span> +
|
||
<span class="hljs-string">'expression'</span>
|
||
);
|
||
}
|
||
<span class="hljs-keyword">return</span> node;
|
||
|
||
<span class="hljs-keyword">case</span> _lt:
|
||
<span class="hljs-keyword">return</span> parseXJSElement();
|
||
|
||
<span class="hljs-keyword">case</span> _xjsText:
|
||
<span class="hljs-keyword">return</span> parseExprAtom();
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
raise(tokStart, <span class="hljs-string">"XJS value should be either an expression or a quoted XJS text"</span>);
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-179">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-179">¶</a>
|
||
</div>
|
||
<p>XJSEmptyExpression is unique type since it doesn’t actually parse anything,
|
||
and so it should start at the end of last read token (left brace) and finish
|
||
at the beginning of the next one (right brace).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSEmptyExpression</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (tokType !== _braceR) {
|
||
unexpected();
|
||
}
|
||
|
||
<span class="hljs-keyword">var</span> tmp;
|
||
|
||
tmp = tokStart;
|
||
tokStart = lastEnd;
|
||
lastEnd = tmp;
|
||
|
||
tmp = tokStartLoc;
|
||
tokStartLoc = lastEndLoc;
|
||
lastEndLoc = tmp;
|
||
|
||
<span class="hljs-keyword">return</span> finishNode(startNode(), <span class="hljs-string">"XJSEmptyExpression"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-180">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-180">¶</a>
|
||
</div>
|
||
<p>Parses JSX expression enclosed into curly brackets.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSExpressionContainer</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
|
||
<span class="hljs-keyword">var</span> origInXJSTag = inXJSTag;
|
||
inXJSTag = <span class="hljs-literal">false</span>;
|
||
|
||
next();
|
||
node.expression = tokType === _braceR ? parseXJSEmptyExpression() : parseExpression();
|
||
|
||
inXJSTag = origInXJSTag;
|
||
|
||
expect(_braceR);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSExpressionContainer"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-181">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-181">¶</a>
|
||
</div>
|
||
<p>Parses following JSX attribute name-value pair.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSAttribute</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">if</span> (tokType === _braceL) {
|
||
<span class="hljs-keyword">var</span> tokStart1 = tokStart, tokStartLoc1 = tokStartLoc;
|
||
|
||
<span class="hljs-keyword">var</span> origInXJSTag = inXJSTag;
|
||
inXJSTag = <span class="hljs-literal">false</span>;
|
||
|
||
next();
|
||
<span class="hljs-keyword">var</span> node = parseSpread();
|
||
|
||
inXJSTag = origInXJSTag;
|
||
|
||
expect(_braceR);
|
||
node.type = <span class="hljs-string">"XJSSpreadAttribute"</span>;
|
||
|
||
node.start = tokStart1;
|
||
node.end = lastEnd;
|
||
<span class="hljs-keyword">if</span> (options.locations) {
|
||
node.loc.start = tokStartLoc1;
|
||
node.loc.end = lastEndLoc;
|
||
}
|
||
<span class="hljs-keyword">if</span> (options.ranges) {
|
||
node.range = [tokStart1, lastEnd];
|
||
}
|
||
|
||
<span class="hljs-keyword">return</span> node;
|
||
}
|
||
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
node.name = parseXJSAttributeName();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-182">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-182">¶</a>
|
||
</div>
|
||
<p>HTML empty attribute</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tokType === _eq) {
|
||
next();
|
||
node.value = parseXJSAttributeValue();
|
||
} <span class="hljs-keyword">else</span> {
|
||
node.value = <span class="hljs-literal">null</span>;
|
||
}
|
||
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSAttribute"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-183">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-183">¶</a>
|
||
</div>
|
||
<p>Parses any type of JSX contents (expression, text or another tag).</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSChild</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">switch</span> (tokType) {
|
||
<span class="hljs-keyword">case</span> _braceL:
|
||
<span class="hljs-keyword">return</span> parseXJSExpressionContainer();
|
||
|
||
<span class="hljs-keyword">case</span> _xjsText:
|
||
<span class="hljs-keyword">return</span> parseExprAtom();
|
||
|
||
<span class="hljs-keyword">default</span>:
|
||
<span class="hljs-keyword">return</span> parseXJSElement();
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-184">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-184">¶</a>
|
||
</div>
|
||
<p>Parses JSX open tag.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSOpeningElement</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode(), attributes = node.attributes = [];
|
||
|
||
<span class="hljs-keyword">var</span> origInXJSChild = inXJSChild;
|
||
<span class="hljs-keyword">var</span> origInXJSTag = inXJSTag;
|
||
inXJSChild = <span class="hljs-literal">false</span>;
|
||
inXJSTag = <span class="hljs-literal">true</span>;
|
||
|
||
next();
|
||
|
||
node.name = parseXJSElementName();
|
||
|
||
<span class="hljs-keyword">while</span> (tokType !== _eof && tokType !== _slash && tokType !== _gt) {
|
||
attributes.push(parseXJSAttribute());
|
||
}
|
||
|
||
inXJSTag = <span class="hljs-literal">false</span>;
|
||
|
||
<span class="hljs-keyword">if</span> (node.selfClosing = !!eat(_slash)) {
|
||
inXJSTag = origInXJSTag;
|
||
inXJSChild = origInXJSChild;
|
||
} <span class="hljs-keyword">else</span> {
|
||
inXJSChild = <span class="hljs-literal">true</span>;
|
||
}
|
||
|
||
expect(_gt);
|
||
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSOpeningElement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-185">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-185">¶</a>
|
||
</div>
|
||
<p>Parses JSX closing tag.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSClosingElement</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
<span class="hljs-keyword">var</span> origInXJSChild = inXJSChild;
|
||
<span class="hljs-keyword">var</span> origInXJSTag = inXJSTag;
|
||
inXJSChild = <span class="hljs-literal">false</span>;
|
||
inXJSTag = <span class="hljs-literal">true</span>;
|
||
tokRegexpAllowed = <span class="hljs-literal">false</span>;
|
||
expect(_ltSlash);
|
||
node.name = parseXJSElementName();
|
||
skipSpace();</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-186">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-186">¶</a>
|
||
</div>
|
||
<p>A valid token is expected after >, so parser needs to know
|
||
whether to look for a standard JS token or an XJS text node</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> inXJSChild = origInXJSChild;
|
||
inXJSTag = origInXJSTag;
|
||
tokRegexpAllowed = <span class="hljs-literal">false</span>;
|
||
expect(_gt);
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSClosingElement"</span>);
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-187">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-187">¶</a>
|
||
</div>
|
||
<p>Parses entire JSX element, including it’s opening tag,
|
||
attributes, contents and closing tag.</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre>
|
||
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseXJSElement</span><span class="hljs-params">()</span> </span>{
|
||
<span class="hljs-keyword">var</span> node = startNode();
|
||
<span class="hljs-keyword">var</span> children = [];
|
||
|
||
<span class="hljs-keyword">var</span> origInXJSChild = inXJSChild;
|
||
<span class="hljs-keyword">var</span> openingElement = parseXJSOpeningElement();
|
||
<span class="hljs-keyword">var</span> closingElement = <span class="hljs-literal">null</span>;
|
||
|
||
<span class="hljs-keyword">if</span> (!openingElement.selfClosing) {
|
||
<span class="hljs-keyword">while</span> (tokType !== _eof && tokType !== _ltSlash) {
|
||
inXJSChild = <span class="hljs-literal">true</span>;
|
||
children.push(parseXJSChild());
|
||
}
|
||
inXJSChild = origInXJSChild;
|
||
closingElement = parseXJSClosingElement();
|
||
<span class="hljs-keyword">if</span> (getQualifiedXJSName(closingElement.name) !== getQualifiedXJSName(openingElement.name)) {
|
||
raise(
|
||
closingElement.start,
|
||
<span class="hljs-string">"Expected corresponding XJS closing tag for '"</span> + getQualifiedXJSName(openingElement.name) + <span class="hljs-string">"'"</span>
|
||
);
|
||
}
|
||
}</pre></div></div>
|
||
|
||
</li>
|
||
|
||
|
||
<li id="section-188">
|
||
<div class="annotation">
|
||
|
||
<div class="pilwrap ">
|
||
<a class="pilcrow" href="#section-188">¶</a>
|
||
</div>
|
||
<p>When (erroneously) writing two adjacent tags like</p>
|
||
<pre><code><span class="hljs-keyword">var</span> x = <span class="xml"><span class="hljs-tag"><<span class="hljs-title">div</span>></span>one<span class="hljs-tag"></<span class="hljs-title">div</span>></span><span class="hljs-tag"><<span class="hljs-title">div</span>></span>two<span class="hljs-tag"></<span class="hljs-title">div</span>></span>;</span>
|
||
</code></pre><p>the default error message is a bit incomprehensible. Since it’s
|
||
rarely (never?) useful to write a less-than sign after an XJS
|
||
element, we disallow it here in the parser in order to provide a
|
||
better error message. (In the rare case that the less-than operator
|
||
was intended, the left tag can be wrapped in parentheses.)</p>
|
||
|
||
</div>
|
||
|
||
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!origInXJSChild && tokType === _lt) {
|
||
raise(tokStart, <span class="hljs-string">"Adjacent XJS elements must be wrapped in an enclosing tag"</span>);
|
||
}
|
||
|
||
node.openingElement = openingElement;
|
||
node.closingElement = closingElement;
|
||
node.children = children;
|
||
<span class="hljs-keyword">return</span> finishNode(node, <span class="hljs-string">"XJSElement"</span>);
|
||
}
|
||
|
||
});</pre></div></div>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
</html>
|