Split up parseStatement()
It was purely interpreted by the V8 engine. Splitting it up allows the individual pieces to be optimized, so less is interpreted.
This commit is contained in:
committed by
Marijn Haverbeke
parent
55b507b715
commit
29feccf3cd
424
acorn.js
424
acorn.js
@@ -1167,211 +1167,245 @@
|
||||
// complexity.
|
||||
|
||||
switch (starttype) {
|
||||
case _break: case _continue:
|
||||
next();
|
||||
var isBreak = starttype === _break;
|
||||
if (eat(_semi) || canInsertSemicolon()) node.label = null;
|
||||
else if (tokType !== _name) unexpected();
|
||||
else {
|
||||
node.label = parseIdent();
|
||||
semicolon();
|
||||
}
|
||||
|
||||
// Verify that there is an actual destination to break or
|
||||
// continue to.
|
||||
for (var i = 0; i < labels.length; ++i) {
|
||||
var lab = labels[i];
|
||||
if (node.label == null || lab.name === node.label.name) {
|
||||
if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
|
||||
if (node.label && isBreak) break;
|
||||
}
|
||||
}
|
||||
if (i === labels.length) raise(node.start, "Unsyntactic " + starttype.keyword);
|
||||
return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
||||
|
||||
case _debugger:
|
||||
next();
|
||||
semicolon();
|
||||
return finishNode(node, "DebuggerStatement");
|
||||
|
||||
case _do:
|
||||
next();
|
||||
labels.push(loopLabel);
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
expect(_while);
|
||||
node.test = parseParenExpression();
|
||||
semicolon();
|
||||
return finishNode(node, "DoWhileStatement");
|
||||
|
||||
// Disambiguating between a `for` and a `for`/`in` loop is
|
||||
// non-trivial. Basically, we have to parse the init `var`
|
||||
// statement or expression, disallowing the `in` operator (see
|
||||
// the second parameter to `parseExpression`), and then check
|
||||
// whether the next token is `in`. When there is no init part
|
||||
// (semicolon immediately after the opening parenthesis), it is
|
||||
// a regular `for` loop.
|
||||
|
||||
case _for:
|
||||
next();
|
||||
labels.push(loopLabel);
|
||||
expect(_parenL);
|
||||
if (tokType === _semi) return parseFor(node, null);
|
||||
if (tokType === _var || tokType === _let) {
|
||||
var varKind = tokType.keyword;
|
||||
var init = startNode();
|
||||
next();
|
||||
parseVar(init, true, varKind);
|
||||
finishNode(init, "VariableDeclaration");
|
||||
if (init.declarations.length === 1 && eat(_in))
|
||||
return parseForIn(node, init);
|
||||
return parseFor(node, init);
|
||||
}
|
||||
var init = parseExpression(false, true);
|
||||
if (eat(_in)) {checkLVal(init); return parseForIn(node, init);}
|
||||
return parseFor(node, init);
|
||||
|
||||
case _function:
|
||||
next();
|
||||
return parseFunction(node, true);
|
||||
|
||||
case _if:
|
||||
next();
|
||||
node.test = parseParenExpression();
|
||||
node.consequent = parseStatement();
|
||||
node.alternate = eat(_else) ? parseStatement() : null;
|
||||
return finishNode(node, "IfStatement");
|
||||
|
||||
case _return:
|
||||
if (!inFunction && !options.allowReturnOutsideFunction)
|
||||
raise(tokStart, "'return' outside of function");
|
||||
next();
|
||||
|
||||
// In `return` (and `break`/`continue`), the keywords with
|
||||
// optional arguments, we eagerly look for a semicolon or the
|
||||
// possibility to insert one.
|
||||
|
||||
if (eat(_semi) || canInsertSemicolon()) node.argument = null;
|
||||
else { node.argument = parseExpression(); semicolon(); }
|
||||
return finishNode(node, "ReturnStatement");
|
||||
|
||||
case _switch:
|
||||
next();
|
||||
node.discriminant = parseParenExpression();
|
||||
node.cases = [];
|
||||
expect(_braceL);
|
||||
labels.push(switchLabel);
|
||||
|
||||
// Statements under must be grouped (by label) in SwitchCase
|
||||
// nodes. `cur` is used to keep the node that we are currently
|
||||
// adding statements to.
|
||||
|
||||
for (var cur, sawDefault; tokType != _braceR;) {
|
||||
if (tokType === _case || tokType === _default) {
|
||||
var isCase = tokType === _case;
|
||||
if (cur) finishNode(cur, "SwitchCase");
|
||||
node.cases.push(cur = startNode());
|
||||
cur.consequent = [];
|
||||
next();
|
||||
if (isCase) cur.test = parseExpression();
|
||||
else {
|
||||
if (sawDefault) raise(lastStart, "Multiple default clauses"); sawDefault = true;
|
||||
cur.test = null;
|
||||
}
|
||||
expect(_colon);
|
||||
} else {
|
||||
if (!cur) unexpected();
|
||||
cur.consequent.push(parseStatement());
|
||||
}
|
||||
}
|
||||
if (cur) finishNode(cur, "SwitchCase");
|
||||
next(); // Closing brace
|
||||
labels.pop();
|
||||
return finishNode(node, "SwitchStatement");
|
||||
|
||||
case _throw:
|
||||
next();
|
||||
if (newline.test(input.slice(lastEnd, tokStart)))
|
||||
raise(lastEnd, "Illegal newline after throw");
|
||||
node.argument = parseExpression();
|
||||
semicolon();
|
||||
return finishNode(node, "ThrowStatement");
|
||||
|
||||
case _try:
|
||||
next();
|
||||
node.block = parseBlock();
|
||||
node.handler = null;
|
||||
if (tokType === _catch) {
|
||||
var clause = startNode();
|
||||
next();
|
||||
expect(_parenL);
|
||||
clause.param = parseIdent();
|
||||
if (strict && isStrictBadIdWord(clause.param.name))
|
||||
raise(clause.param.start, "Binding " + clause.param.name + " in strict mode");
|
||||
expect(_parenR);
|
||||
clause.guard = null;
|
||||
clause.body = parseBlock();
|
||||
node.handler = finishNode(clause, "CatchClause");
|
||||
}
|
||||
node.guardedHandlers = empty;
|
||||
node.finalizer = eat(_finally) ? parseBlock() : null;
|
||||
if (!node.handler && !node.finalizer)
|
||||
raise(node.start, "Missing catch or finally clause");
|
||||
return finishNode(node, "TryStatement");
|
||||
|
||||
case _const:
|
||||
case _let:
|
||||
case _var:
|
||||
next();
|
||||
parseVar(node, false, starttype.keyword);
|
||||
semicolon();
|
||||
return finishNode(node, "VariableDeclaration");
|
||||
|
||||
case _while:
|
||||
next();
|
||||
node.test = parseParenExpression();
|
||||
labels.push(loopLabel);
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
return finishNode(node, "WhileStatement");
|
||||
|
||||
case _with:
|
||||
if (strict) raise(tokStart, "'with' in strict mode");
|
||||
next();
|
||||
node.object = parseParenExpression();
|
||||
node.body = parseStatement();
|
||||
return finishNode(node, "WithStatement");
|
||||
|
||||
case _braceL:
|
||||
return parseBlock();
|
||||
|
||||
case _semi:
|
||||
next();
|
||||
return finishNode(node, "EmptyStatement");
|
||||
case _break: case _continue: return parseBreakContinueStatement(node, starttype.keyword);
|
||||
case _debugger: return parseDebuggerStatement(node);
|
||||
case _do: return parseDoStatement(node);
|
||||
case _for: return parseForStatement(node);
|
||||
case _function: return parseFunctionStatement(node);
|
||||
case _if: return parseIfStatement(node);
|
||||
case _return: return parseReturnStatement(node);
|
||||
case _switch: return parseSwitchStatement(node);
|
||||
case _throw: return parseThrowStatement(node);
|
||||
case _try: return parseTryStatement(node);
|
||||
case _var: case _let: case _const: return parseVarStatement(node, starttype.keyword);
|
||||
case _while: return parseWhileStatement(node);
|
||||
case _with: return parseWithStatement(node);
|
||||
case _braceL: return parseBlock(); // no point creating a function for this
|
||||
case _semi: return parseEmptyStatement(node);
|
||||
|
||||
// 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.
|
||||
|
||||
default:
|
||||
var maybeName = tokVal, expr = parseExpression();
|
||||
if (starttype === _name && expr.type === "Identifier" && eat(_colon)) {
|
||||
for (var i = 0; i < labels.length; ++i)
|
||||
if (labels[i].name === maybeName) raise(expr.start, "Label '" + maybeName + "' is already declared");
|
||||
var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null;
|
||||
labels.push({name: maybeName, kind: kind});
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
node.label = expr;
|
||||
return finishNode(node, "LabeledStatement");
|
||||
} else {
|
||||
node.expression = expr;
|
||||
semicolon();
|
||||
return finishNode(node, "ExpressionStatement");
|
||||
if (starttype === _name && expr.type === "Identifier" && eat(_colon))
|
||||
return parseLabeledStatement(node, maybeName, expr);
|
||||
else return parseExpressionStatement(node, expr);
|
||||
}
|
||||
}
|
||||
|
||||
function parseBreakContinueStatement(node, keyword) {
|
||||
var isBreak = keyword == "break";
|
||||
next();
|
||||
if (eat(_semi) || canInsertSemicolon()) node.label = null;
|
||||
else if (tokType !== _name) unexpected();
|
||||
else {
|
||||
node.label = parseIdent();
|
||||
semicolon();
|
||||
}
|
||||
|
||||
// Verify that there is an actual destination to break or
|
||||
// continue to.
|
||||
for (var i = 0; i < labels.length; ++i) {
|
||||
var lab = labels[i];
|
||||
if (node.label == null || lab.name === node.label.name) {
|
||||
if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
|
||||
if (node.label && isBreak) break;
|
||||
}
|
||||
}
|
||||
if (i === labels.length) raise(node.start, "Unsyntactic " + keyword);
|
||||
return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
||||
}
|
||||
|
||||
function parseDebuggerStatement(node) {
|
||||
next();
|
||||
semicolon();
|
||||
return finishNode(node, "DebuggerStatement");
|
||||
}
|
||||
|
||||
function parseDoStatement(node) {
|
||||
next();
|
||||
labels.push(loopLabel);
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
expect(_while);
|
||||
node.test = parseParenExpression();
|
||||
semicolon();
|
||||
return finishNode(node, "DoWhileStatement");
|
||||
}
|
||||
|
||||
// Disambiguating between a `for` and a `for`/`in` loop is
|
||||
// non-trivial. Basically, we have to parse the init `var`
|
||||
// statement or expression, disallowing the `in` operator (see
|
||||
// the second parameter to `parseExpression`), and then check
|
||||
// whether the next token is `in`. When there is no init part
|
||||
// (semicolon immediately after the opening parenthesis), it is
|
||||
// a regular `for` loop.
|
||||
|
||||
function parseForStatement(node) {
|
||||
next();
|
||||
labels.push(loopLabel);
|
||||
expect(_parenL);
|
||||
if (tokType === _semi) return parseFor(node, null);
|
||||
if (tokType === _var || tokType === _let) {
|
||||
var init = startNode(), varKind = tokType.keyword;
|
||||
next();
|
||||
parseVar(init, true, varKind);
|
||||
finishNode(init, "VariableDeclaration");
|
||||
if (init.declarations.length === 1 && eat(_in))
|
||||
return parseForIn(node, init);
|
||||
return parseFor(node, init);
|
||||
}
|
||||
var init = parseExpression(false, true);
|
||||
if (eat(_in)) {checkLVal(init); return parseForIn(node, init);}
|
||||
return parseFor(node, init);
|
||||
}
|
||||
|
||||
function parseFunctionStatement(node) {
|
||||
next();
|
||||
return parseFunction(node, true);
|
||||
}
|
||||
|
||||
function parseIfStatement(node) {
|
||||
next();
|
||||
node.test = parseParenExpression();
|
||||
node.consequent = parseStatement();
|
||||
node.alternate = eat(_else) ? parseStatement() : null;
|
||||
return finishNode(node, "IfStatement");
|
||||
}
|
||||
|
||||
function parseReturnStatement(node) {
|
||||
if (!inFunction && !options.allowReturnOutsideFunction)
|
||||
raise(tokStart, "'return' outside of function");
|
||||
next();
|
||||
|
||||
// In `return` (and `break`/`continue`), the keywords with
|
||||
// optional arguments, we eagerly look for a semicolon or the
|
||||
// possibility to insert one.
|
||||
|
||||
if (eat(_semi) || canInsertSemicolon()) node.argument = null;
|
||||
else { node.argument = parseExpression(); semicolon(); }
|
||||
return finishNode(node, "ReturnStatement");
|
||||
}
|
||||
|
||||
function parseSwitchStatement(node) {
|
||||
next();
|
||||
node.discriminant = parseParenExpression();
|
||||
node.cases = [];
|
||||
expect(_braceL);
|
||||
labels.push(switchLabel);
|
||||
|
||||
// Statements under must be grouped (by label) in SwitchCase
|
||||
// nodes. `cur` is used to keep the node that we are currently
|
||||
// adding statements to.
|
||||
|
||||
for (var cur, sawDefault; tokType != _braceR;) {
|
||||
if (tokType === _case || tokType === _default) {
|
||||
var isCase = tokType === _case;
|
||||
if (cur) finishNode(cur, "SwitchCase");
|
||||
node.cases.push(cur = startNode());
|
||||
cur.consequent = [];
|
||||
next();
|
||||
if (isCase) cur.test = parseExpression();
|
||||
else {
|
||||
if (sawDefault) raise(lastStart, "Multiple default clauses"); sawDefault = true;
|
||||
cur.test = null;
|
||||
}
|
||||
expect(_colon);
|
||||
} else {
|
||||
if (!cur) unexpected();
|
||||
cur.consequent.push(parseStatement());
|
||||
}
|
||||
}
|
||||
if (cur) finishNode(cur, "SwitchCase");
|
||||
next(); // Closing brace
|
||||
labels.pop();
|
||||
return finishNode(node, "SwitchStatement");
|
||||
}
|
||||
|
||||
function parseThrowStatement(node) {
|
||||
next();
|
||||
if (newline.test(input.slice(lastEnd, tokStart)))
|
||||
raise(lastEnd, "Illegal newline after throw");
|
||||
node.argument = parseExpression();
|
||||
semicolon();
|
||||
return finishNode(node, "ThrowStatement");next();
|
||||
if (newline.test(input.slice(lastEnd, tokStart)))
|
||||
raise(lastEnd, "Illegal newline after throw");
|
||||
node.argument = parseExpression();
|
||||
semicolon();
|
||||
return finishNode(node, "ThrowStatement");
|
||||
}
|
||||
|
||||
function parseTryStatement(node) {
|
||||
next();
|
||||
node.block = parseBlock();
|
||||
node.handler = null;
|
||||
if (tokType === _catch) {
|
||||
var clause = startNode();
|
||||
next();
|
||||
expect(_parenL);
|
||||
clause.param = parseIdent();
|
||||
if (strict && isStrictBadIdWord(clause.param.name))
|
||||
raise(clause.param.start, "Binding " + clause.param.name + " in strict mode");
|
||||
expect(_parenR);
|
||||
clause.guard = null;
|
||||
clause.body = parseBlock();
|
||||
node.handler = finishNode(clause, "CatchClause");
|
||||
}
|
||||
node.guardedHandlers = empty;
|
||||
node.finalizer = eat(_finally) ? parseBlock() : null;
|
||||
if (!node.handler && !node.finalizer)
|
||||
raise(node.start, "Missing catch or finally clause");
|
||||
return finishNode(node, "TryStatement");
|
||||
}
|
||||
|
||||
function parseVarStatement(node, kind) {
|
||||
next();
|
||||
parseVar(node, false, kind);
|
||||
semicolon();
|
||||
return finishNode(node, "VariableDeclaration");
|
||||
}
|
||||
|
||||
function parseWhileStatement(node) {
|
||||
next();
|
||||
node.test = parseParenExpression();
|
||||
labels.push(loopLabel);
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
return finishNode(node, "WhileStatement");
|
||||
}
|
||||
|
||||
function parseWithStatement(node) {
|
||||
if (strict) raise(tokStart, "'with' in strict mode");
|
||||
next();
|
||||
node.object = parseParenExpression();
|
||||
node.body = parseStatement();
|
||||
return finishNode(node, "WithStatement");
|
||||
}
|
||||
|
||||
function parseEmptyStatement(node) {
|
||||
next();
|
||||
return finishNode(node, "EmptyStatement");
|
||||
}
|
||||
|
||||
function parseLabeledStatement(node, maybeName, expr) {
|
||||
for (var i = 0; i < labels.length; ++i)
|
||||
if (labels[i].name === maybeName) raise(expr.start, "Label '" + maybeName + "' is already declared");
|
||||
var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null;
|
||||
labels.push({name: maybeName, kind: kind});
|
||||
node.body = parseStatement();
|
||||
labels.pop();
|
||||
node.label = expr;
|
||||
return finishNode(node, "LabeledStatement");
|
||||
}
|
||||
|
||||
function parseExpressionStatement(node, expr) {
|
||||
node.expression = expr;
|
||||
semicolon();
|
||||
return finishNode(node, "ExpressionStatement");
|
||||
}
|
||||
|
||||
// Used for constructs like `switch` and `if` that insist on
|
||||
|
||||
395
index.html
395
index.html
@@ -832,192 +832,229 @@ does not help.</p> </td> <td class="code">
|
||||
<span class="kd">var</span> <span class="nx">starttype</span> <span class="o">=</span> <span class="nx">tokType</span><span class="p">,</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-97">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">switch</span> <span class="p">(</span><span class="nx">starttype</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">case</span> <span class="nx">_break</span><span class="o">:</span> <span class="k">case</span> <span class="nx">_continue</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="kd">var</span> <span class="nx">isBreak</span> <span class="o">=</span> <span class="nx">starttype</span> <span class="o">===</span> <span class="nx">_break</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_semi</span><span class="p">)</span> <span class="o">||</span> <span class="nx">canInsertSemicolon</span><span class="p">())</span> <span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">!==</span> <span class="nx">_name</span><span class="p">)</span> <span class="nx">unexpected</span><span class="p">();</span>
|
||||
<span class="k">else</span> <span class="p">{</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="nx">parseIdent</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">¶</a> </div> <p>Verify that there is an actual destination to break or
|
||||
continue to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">lab</span> <span class="o">=</span> <span class="nx">labels</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="nx">lab</span><span class="p">.</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">node</span><span class="p">.</span><span class="nx">label</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">lab</span><span class="p">.</span><span class="nx">kind</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="p">(</span><span class="nx">isBreak</span> <span class="o">||</span> <span class="nx">lab</span><span class="p">.</span><span class="nx">kind</span> <span class="o">===</span> <span class="s2">"loop"</span><span class="p">))</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">&&</span> <span class="nx">isBreak</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">===</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Unsyntactic "</span> <span class="o">+</span> <span class="nx">starttype</span><span class="p">.</span><span class="nx">keyword</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">isBreak</span> <span class="o">?</span> <span class="s2">"BreakStatement"</span> <span class="o">:</span> <span class="s2">"ContinueStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_debugger</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"DebuggerStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_do</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_while</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"DoWhileStatement"</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">¶</a> </div> <p>Disambiguating between a <code>for</code> and a <code>for</code>/<code>in</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>. When there is no init part
|
||||
(semicolon immediately after the opening parenthesis), it is
|
||||
a regular <code>for</code> loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">case</span> <span class="nx">_for</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenL</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_semi</span><span class="p">)</span> <span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_var</span> <span class="o">||</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_let</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">varKind</span> <span class="o">=</span> <span class="nx">tokType</span><span class="p">.</span><span class="nx">keyword</span><span class="p">;</span>
|
||||
<span class="kd">var</span> <span class="nx">init</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">();</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">parseVar</span><span class="p">(</span><span class="nx">init</span><span class="p">,</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">varKind</span><span class="p">);</span>
|
||||
<span class="nx">finishNode</span><span class="p">(</span><span class="nx">init</span><span class="p">,</span> <span class="s2">"VariableDeclaration"</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">init</span><span class="p">.</span><span class="nx">declarations</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">1</span> <span class="o">&&</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_in</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="nx">parseForIn</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="kd">var</span> <span class="nx">init</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">(</span><span class="kc">false</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_in</span><span class="p">))</span> <span class="p">{</span><span class="nx">checkLVal</span><span class="p">(</span><span class="nx">init</span><span class="p">);</span> <span class="k">return</span> <span class="nx">parseForIn</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);}</span>
|
||||
<span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_function</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">parseFunction</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_if</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">consequent</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">alternate</span> <span class="o">=</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_else</span><span class="p">)</span> <span class="o">?</span> <span class="nx">parseStatement</span><span class="p">()</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"IfStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_return</span><span class="o">:</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">inFunction</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">options</span><span class="p">.</span><span class="nx">allowReturnOutsideFunction</span><span class="p">)</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">tokStart</span><span class="p">,</span> <span class="s2">"'return' outside of function"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_semi</span><span class="p">)</span> <span class="o">||</span> <span class="nx">canInsertSemicolon</span><span class="p">())</span> <span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">else</span> <span class="p">{</span> <span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span> <span class="nx">semicolon</span><span class="p">();</span> <span class="p">}</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ReturnStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_switch</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">discriminant</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">cases</span> <span class="o">=</span> <span class="p">[];</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_braceL</span><span class="p">);</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">switchLabel</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">cur</span><span class="p">,</span> <span class="nx">sawDefault</span><span class="p">;</span> <span class="nx">tokType</span> <span class="o">!=</span> <span class="nx">_braceR</span><span class="p">;)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_case</span> <span class="o">||</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_default</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">isCase</span> <span class="o">=</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_case</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">cur</span><span class="p">,</span> <span class="s2">"SwitchCase"</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">cases</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">cur</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">());</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">consequent</span> <span class="o">=</span> <span class="p">[];</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">isCase</span><span class="p">)</span> <span class="nx">cur</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="k">else</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">sawDefault</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">lastStart</span><span class="p">,</span> <span class="s2">"Multiple default clauses"</span><span class="p">);</span> <span class="nx">sawDefault</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_colon</span><span class="p">);</span>
|
||||
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">unexpected</span><span class="p">();</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">consequent</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">parseStatement</span><span class="p">());</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">cur</span><span class="p">,</span> <span class="s2">"SwitchCase"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span> <span class="c1">// Closing brace</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"SwitchStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_throw</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">newline</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="nx">tokStart</span><span class="p">)))</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="s2">"Illegal newline after throw"</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ThrowStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_try</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">block</span> <span class="o">=</span> <span class="nx">parseBlock</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_catch</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">clause</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">();</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenL</span><span class="p">);</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">param</span> <span class="o">=</span> <span class="nx">parseIdent</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">strict</span> <span class="o">&&</span> <span class="nx">isStrictBadIdWord</span><span class="p">(</span><span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">name</span><span class="p">))</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Binding "</span> <span class="o">+</span> <span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">" in strict mode"</span><span class="p">);</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenR</span><span class="p">);</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">guard</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseBlock</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">clause</span><span class="p">,</span> <span class="s2">"CatchClause"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">guardedHandlers</span> <span class="o">=</span> <span class="nx">empty</span><span class="p">;</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">finalizer</span> <span class="o">=</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_finally</span><span class="p">)</span> <span class="o">?</span> <span class="nx">parseBlock</span><span class="p">()</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">node</span><span class="p">.</span><span class="nx">finalizer</span><span class="p">)</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Missing catch or finally clause"</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"TryStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_const</span><span class="o">:</span>
|
||||
<span class="k">case</span> <span class="nx">_let</span><span class="o">:</span>
|
||||
<span class="k">case</span> <span class="nx">_var</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">parseVar</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">starttype</span><span class="p">.</span><span class="nx">keyword</span><span class="p">);</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"VariableDeclaration"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_while</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"WhileStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_with</span><span class="o">:</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">strict</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">tokStart</span><span class="p">,</span> <span class="s2">"'with' in strict mode"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">object</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"WithStatement"</span><span class="p">);</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_braceL</span><span class="o">:</span>
|
||||
<span class="k">return</span> <span class="nx">parseBlock</span><span class="p">();</span>
|
||||
|
||||
<span class="k">case</span> <span class="nx">_semi</span><span class="o">:</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"EmptyStatement"</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">¶</a> </div> <p>If the statement does not start with a statement keyword or a
|
||||
<span class="k">case</span> <span class="nx">_break</span><span class="o">:</span> <span class="k">case</span> <span class="nx">_continue</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseBreakContinueStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">starttype</span><span class="p">.</span><span class="nx">keyword</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_debugger</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseDebuggerStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_do</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseDoStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_for</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseForStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_function</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseFunctionStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_if</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseIfStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_return</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseReturnStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_switch</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseSwitchStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_throw</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseThrowStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_try</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseTryStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_var</span><span class="o">:</span> <span class="k">case</span> <span class="nx">_let</span><span class="o">:</span> <span class="k">case</span> <span class="nx">_const</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseVarStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">starttype</span><span class="p">.</span><span class="nx">keyword</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_while</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseWhileStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_with</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseWithStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
|
||||
<span class="k">case</span> <span class="nx">_braceL</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseBlock</span><span class="p">();</span> <span class="c1">// no point creating a function for this</span>
|
||||
<span class="k">case</span> <span class="nx">_semi</span><span class="o">:</span> <span class="k">return</span> <span class="nx">parseEmptyStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">default</span><span class="o">:</span>
|
||||
<span class="kd">var</span> <span class="nx">maybeName</span> <span class="o">=</span> <span class="nx">tokVal</span><span class="p">,</span> <span class="nx">expr</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">starttype</span> <span class="o">===</span> <span class="nx">_name</span> <span class="o">&&</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">"Identifier"</span> <span class="o">&&</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_colon</span><span class="p">))</span> <span class="p">{</span>
|
||||
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">labels</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">maybeName</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">expr</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Label '"</span> <span class="o">+</span> <span class="nx">maybeName</span> <span class="o">+</span> <span class="s2">"' is already declared"</span><span class="p">);</span>
|
||||
<span class="kd">var</span> <span class="nx">kind</span> <span class="o">=</span> <span class="nx">tokType</span><span class="p">.</span><span class="nx">isLoop</span> <span class="o">?</span> <span class="s2">"loop"</span> <span class="o">:</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_switch</span> <span class="o">?</span> <span class="s2">"switch"</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="nx">name</span><span class="o">:</span> <span class="nx">maybeName</span><span class="p">,</span> <span class="nx">kind</span><span class="o">:</span> <span class="nx">kind</span><span class="p">});</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">;</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"LabeledStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">expression</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">;</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ExpressionStatement"</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">starttype</span> <span class="o">===</span> <span class="nx">_name</span> <span class="o">&&</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">"Identifier"</span> <span class="o">&&</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_colon</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="nx">parseLabeledStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">maybeName</span><span class="p">,</span> <span class="nx">expr</span><span class="p">);</span>
|
||||
<span class="k">else</span> <span class="k">return</span> <span class="nx">parseExpressionStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">expr</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseBreakContinueStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">keyword</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">isBreak</span> <span class="o">=</span> <span class="nx">keyword</span> <span class="o">==</span> <span class="s2">"break"</span><span class="p">;</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_semi</span><span class="p">)</span> <span class="o">||</span> <span class="nx">canInsertSemicolon</span><span class="p">())</span> <span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">!==</span> <span class="nx">_name</span><span class="p">)</span> <span class="nx">unexpected</span><span class="p">();</span>
|
||||
<span class="k">else</span> <span class="p">{</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="nx">parseIdent</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">¶</a> </div> <p>Verify that there is an actual destination to break or
|
||||
continue to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">lab</span> <span class="o">=</span> <span class="nx">labels</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="nx">lab</span><span class="p">.</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">node</span><span class="p">.</span><span class="nx">label</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">lab</span><span class="p">.</span><span class="nx">kind</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="p">(</span><span class="nx">isBreak</span> <span class="o">||</span> <span class="nx">lab</span><span class="p">.</span><span class="nx">kind</span> <span class="o">===</span> <span class="s2">"loop"</span><span class="p">))</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">&&</span> <span class="nx">isBreak</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">===</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Unsyntactic "</span> <span class="o">+</span> <span class="nx">keyword</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">isBreak</span> <span class="o">?</span> <span class="s2">"BreakStatement"</span> <span class="o">:</span> <span class="s2">"ContinueStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseDebuggerStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"DebuggerStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseDoStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_while</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"DoWhileStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">¶</a> </div> <p>Disambiguating between a <code>for</code> and a <code>for</code>/<code>in</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>. When there is no init part
|
||||
(semicolon immediately after the opening parenthesis), it is
|
||||
a regular <code>for</code> loop.</p> </td> <td class="code"> <div class="highlight"><pre>
|
||||
<span class="kd">function</span> <span class="nx">parseForStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenL</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_semi</span><span class="p">)</span> <span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_var</span> <span class="o">||</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_let</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">init</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">(),</span> <span class="nx">varKind</span> <span class="o">=</span> <span class="nx">tokType</span><span class="p">.</span><span class="nx">keyword</span><span class="p">;</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">parseVar</span><span class="p">(</span><span class="nx">init</span><span class="p">,</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">varKind</span><span class="p">);</span>
|
||||
<span class="nx">finishNode</span><span class="p">(</span><span class="nx">init</span><span class="p">,</span> <span class="s2">"VariableDeclaration"</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">init</span><span class="p">.</span><span class="nx">declarations</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">1</span> <span class="o">&&</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_in</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="nx">parseForIn</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="kd">var</span> <span class="nx">init</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">(</span><span class="kc">false</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_in</span><span class="p">))</span> <span class="p">{</span><span class="nx">checkLVal</span><span class="p">(</span><span class="nx">init</span><span class="p">);</span> <span class="k">return</span> <span class="nx">parseForIn</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);}</span>
|
||||
<span class="k">return</span> <span class="nx">parseFor</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">init</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseFunctionStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">parseFunction</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseIfStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">consequent</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">alternate</span> <span class="o">=</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_else</span><span class="p">)</span> <span class="o">?</span> <span class="nx">parseStatement</span><span class="p">()</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"IfStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseReturnStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">inFunction</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">options</span><span class="p">.</span><span class="nx">allowReturnOutsideFunction</span><span class="p">)</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">tokStart</span><span class="p">,</span> <span class="s2">"'return' outside of function"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">eat</span><span class="p">(</span><span class="nx">_semi</span><span class="p">)</span> <span class="o">||</span> <span class="nx">canInsertSemicolon</span><span class="p">())</span> <span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">else</span> <span class="p">{</span> <span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span> <span class="nx">semicolon</span><span class="p">();</span> <span class="p">}</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ReturnStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseSwitchStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">discriminant</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">cases</span> <span class="o">=</span> <span class="p">[];</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_braceL</span><span class="p">);</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">switchLabel</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">¶</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> </td> <td class="code"> <div class="highlight"><pre> <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">cur</span><span class="p">,</span> <span class="nx">sawDefault</span><span class="p">;</span> <span class="nx">tokType</span> <span class="o">!=</span> <span class="nx">_braceR</span><span class="p">;)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_case</span> <span class="o">||</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_default</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">isCase</span> <span class="o">=</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_case</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">cur</span><span class="p">,</span> <span class="s2">"SwitchCase"</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">cases</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">cur</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">());</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">consequent</span> <span class="o">=</span> <span class="p">[];</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">isCase</span><span class="p">)</span> <span class="nx">cur</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="k">else</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">sawDefault</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">lastStart</span><span class="p">,</span> <span class="s2">"Multiple default clauses"</span><span class="p">);</span> <span class="nx">sawDefault</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_colon</span><span class="p">);</span>
|
||||
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">unexpected</span><span class="p">();</span>
|
||||
<span class="nx">cur</span><span class="p">.</span><span class="nx">consequent</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">parseStatement</span><span class="p">());</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">cur</span><span class="p">)</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">cur</span><span class="p">,</span> <span class="s2">"SwitchCase"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span> <span class="c1">// Closing brace</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"SwitchStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseThrowStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">newline</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="nx">tokStart</span><span class="p">)))</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="s2">"Illegal newline after throw"</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ThrowStatement"</span><span class="p">);</span><span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">newline</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="nx">tokStart</span><span class="p">)))</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">lastEnd</span><span class="p">,</span> <span class="s2">"Illegal newline after throw"</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">argument</span> <span class="o">=</span> <span class="nx">parseExpression</span><span class="p">();</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ThrowStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseTryStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">block</span> <span class="o">=</span> <span class="nx">parseBlock</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_catch</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="kd">var</span> <span class="nx">clause</span> <span class="o">=</span> <span class="nx">startNode</span><span class="p">();</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenL</span><span class="p">);</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">param</span> <span class="o">=</span> <span class="nx">parseIdent</span><span class="p">();</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">strict</span> <span class="o">&&</span> <span class="nx">isStrictBadIdWord</span><span class="p">(</span><span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">name</span><span class="p">))</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Binding "</span> <span class="o">+</span> <span class="nx">clause</span><span class="p">.</span><span class="nx">param</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">" in strict mode"</span><span class="p">);</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenR</span><span class="p">);</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">guard</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="nx">clause</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseBlock</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">clause</span><span class="p">,</span> <span class="s2">"CatchClause"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">guardedHandlers</span> <span class="o">=</span> <span class="nx">empty</span><span class="p">;</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">finalizer</span> <span class="o">=</span> <span class="nx">eat</span><span class="p">(</span><span class="nx">_finally</span><span class="p">)</span> <span class="o">?</span> <span class="nx">parseBlock</span><span class="p">()</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">node</span><span class="p">.</span><span class="nx">handler</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">node</span><span class="p">.</span><span class="nx">finalizer</span><span class="p">)</span>
|
||||
<span class="nx">raise</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Missing catch or finally clause"</span><span class="p">);</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"TryStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseVarStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">kind</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">parseVar</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">kind</span><span class="p">);</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"VariableDeclaration"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseWhileStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">test</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">loopLabel</span><span class="p">);</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"WhileStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseWithStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">strict</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">tokStart</span><span class="p">,</span> <span class="s2">"'with' in strict mode"</span><span class="p">);</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">object</span> <span class="o">=</span> <span class="nx">parseParenExpression</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"WithStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseEmptyStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">next</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"EmptyStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseLabeledStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">maybeName</span><span class="p">,</span> <span class="nx">expr</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">labels</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nx">labels</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">name</span> <span class="o">===</span> <span class="nx">maybeName</span><span class="p">)</span> <span class="nx">raise</span><span class="p">(</span><span class="nx">expr</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="s2">"Label '"</span> <span class="o">+</span> <span class="nx">maybeName</span> <span class="o">+</span> <span class="s2">"' is already declared"</span><span class="p">);</span>
|
||||
<span class="kd">var</span> <span class="nx">kind</span> <span class="o">=</span> <span class="nx">tokType</span><span class="p">.</span><span class="nx">isLoop</span> <span class="o">?</span> <span class="s2">"loop"</span> <span class="o">:</span> <span class="nx">tokType</span> <span class="o">===</span> <span class="nx">_switch</span> <span class="o">?</span> <span class="s2">"switch"</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="nx">name</span><span class="o">:</span> <span class="nx">maybeName</span><span class="p">,</span> <span class="nx">kind</span><span class="o">:</span> <span class="nx">kind</span><span class="p">});</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">body</span> <span class="o">=</span> <span class="nx">parseStatement</span><span class="p">();</span>
|
||||
<span class="nx">labels</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">label</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">;</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"LabeledStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="kd">function</span> <span class="nx">parseExpressionStatement</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">expr</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">expression</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">;</span>
|
||||
<span class="nx">semicolon</span><span class="p">();</span>
|
||||
<span class="k">return</span> <span class="nx">finishNode</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="s2">"ExpressionStatement"</span><span class="p">);</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-103">¶</a> </div> <p>Used for constructs like <code>switch</code> and <code>if</code> that insist on
|
||||
parentheses around their expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">parseParenExpression</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="nx">expect</span><span class="p">(</span><span class="nx">_parenL</span><span class="p">);</span>
|
||||
|
||||
Reference in New Issue
Block a user