Simplify the parser by removing the need for the 'force' parameter.

This commit is contained in:
Cyrus Najmabadi 2014-11-29 15:08:59 -08:00
parent b1f49c44f9
commit ac5e9b6c88

View file

@ -2237,7 +2237,7 @@ module TypeScript.Parser {
return new OmittedExpressionSyntax(contextFlags); return new OmittedExpressionSyntax(contextFlags);
} }
return allowInAnd(tryParseAssignmentExpressionOrHigher); return isExpression(currentToken()) ? allowInAnd(parseAssignmentExpressionOrHigher) : undefined;
} }
function isExpression(currentToken: ISyntaxToken): boolean { function isExpression(currentToken: ISyntaxToken): boolean {
@ -2520,19 +2520,11 @@ module TypeScript.Parser {
return leftOperand; return leftOperand;
} }
function tryParseAssignmentExpressionOrHigher(): IExpressionSyntax {
return tryParseAssignmentExpressionOrHigherWorker(/*force:*/ false);
}
function parseAssignmentExpressionOrHigher(): IExpressionSyntax {
return tryParseAssignmentExpressionOrHigherWorker(/*force:*/ true);
}
// Called when you need to parse an expression, but you do not want to allow 'CommaExpressions'. // Called when you need to parse an expression, but you do not want to allow 'CommaExpressions'.
// i.e. if you have "var a = 1, b = 2" then when we parse '1' we want to parse with higher // i.e. if you have "var a = 1, b = 2" then when we parse '1' we want to parse with higher
// precedence than 'comma'. Otherwise we'll get: "var a = (1, (b = 2))", instead of // precedence than 'comma'. Otherwise we'll get: "var a = (1, (b = 2))", instead of
// "var a = (1), b = (2)"); // "var a = (1), b = (2)");
function tryParseAssignmentExpressionOrHigherWorker(force: boolean): IExpressionSyntax { function parseAssignmentExpressionOrHigher(): IExpressionSyntax {
// AssignmentExpression[in,yield]: // AssignmentExpression[in,yield]:
// 1) ConditionalExpression[?in,?yield] // 1) ConditionalExpression[?in,?yield]
// 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
@ -2566,11 +2558,7 @@ module TypeScript.Parser {
// Otherwise, we try to parse out the conditional expression bit. We want to allow any // Otherwise, we try to parse out the conditional expression bit. We want to allow any
// binary expression here, so we pass in the 'lowest' precedence here so that it matches // binary expression here, so we pass in the 'lowest' precedence here so that it matches
// and consumes anything. // and consumes anything.
var leftOperand = tryParseBinaryExpressionOrHigher(_currentToken, force, BinaryExpressionPrecedence.Lowest); var leftOperand = parseBinaryExpressionOrHigher(_currentToken, BinaryExpressionPrecedence.Lowest);
if (leftOperand === undefined) {
return undefined;
}
if (SyntaxUtilities.isLeftHandSizeExpression(leftOperand)) { if (SyntaxUtilities.isLeftHandSizeExpression(leftOperand)) {
// Note: we call currentOperatorToken so that we get an appropriately merged token // Note: we call currentOperatorToken so that we get an appropriately merged token
// for cases like > > = becoming >>= // for cases like > > = becoming >>=
@ -2614,7 +2602,7 @@ module TypeScript.Parser {
} }
// Not an 'await' expression. Parse this with our normal postfix parsing rules. // Not an 'await' expression. Parse this with our normal postfix parsing rules.
return tryParsePostfixExpressionOrHigher(awaitKeyword, /*force:*/ true); return parsePostfixExpressionOrHigher(awaitKeyword);
} }
function parseAwaitExpression(awaitKeyword: ISyntaxToken): AwaitExpressionSyntax { function parseAwaitExpression(awaitKeyword: ISyntaxToken): AwaitExpressionSyntax {
@ -2727,7 +2715,7 @@ module TypeScript.Parser {
: tryParseParenthesizedArrowFunctionExpression(); : tryParseParenthesizedArrowFunctionExpression();
} }
function tryParseUnaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): IUnaryExpressionSyntax { function parseUnaryExpressionOrHigher(_currentToken: ISyntaxToken): IUnaryExpressionSyntax {
var currentTokenKind = _currentToken.kind; var currentTokenKind = _currentToken.kind;
switch (currentTokenKind) { switch (currentTokenKind) {
@ -2737,7 +2725,7 @@ module TypeScript.Parser {
case SyntaxKind.ExclamationToken: case SyntaxKind.ExclamationToken:
case SyntaxKind.PlusPlusToken: case SyntaxKind.PlusPlusToken:
case SyntaxKind.MinusMinusToken: case SyntaxKind.MinusMinusToken:
return new PrefixUnaryExpressionSyntax(contextFlags, consumeToken(_currentToken), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); return new PrefixUnaryExpressionSyntax(contextFlags, consumeToken(_currentToken), parseUnaryExpressionOrHigher(currentToken()));
case SyntaxKind.TypeOfKeyword: case SyntaxKind.TypeOfKeyword:
return parseTypeOfExpression(_currentToken); return parseTypeOfExpression(_currentToken);
case SyntaxKind.VoidKeyword: case SyntaxKind.VoidKeyword:
@ -2749,11 +2737,11 @@ module TypeScript.Parser {
case SyntaxKind.AwaitKeyword: case SyntaxKind.AwaitKeyword:
return parsePossibleAwaitExpression(_currentToken); return parsePossibleAwaitExpression(_currentToken);
default: default:
return tryParsePostfixExpressionOrHigher(_currentToken, force); return parsePostfixExpressionOrHigher(_currentToken);
} }
} }
function tryParseBinaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean, precedence: BinaryExpressionPrecedence): IExpressionSyntax { function parseBinaryExpressionOrHigher(_currentToken: ISyntaxToken, precedence: BinaryExpressionPrecedence): IExpressionSyntax {
// The binary expressions are incredibly left recursive in their definitions. We // The binary expressions are incredibly left recursive in their definitions. We
// clearly can't implement that through recursion. So, instead, we first bottom out // clearly can't implement that through recursion. So, instead, we first bottom out
// of all the recursion by jumping to this production and consuming a UnaryExpression // of all the recursion by jumping to this production and consuming a UnaryExpression
@ -2761,10 +2749,7 @@ module TypeScript.Parser {
// //
// MultiplicativeExpression: See 11.5 // MultiplicativeExpression: See 11.5
// UnaryExpression // UnaryExpression
var leftOperand = tryParseUnaryExpressionOrHigher(_currentToken, force); var leftOperand = parseUnaryExpressionOrHigher(_currentToken);
if (leftOperand === undefined) {
return undefined;
}
// We then pop up the stack consuming the other side of the binary exprssion if it exists. // We then pop up the stack consuming the other side of the binary exprssion if it exists.
return parseBinaryExpressionRest(precedence, leftOperand); return parseBinaryExpressionRest(precedence, leftOperand);
@ -2828,7 +2813,7 @@ module TypeScript.Parser {
// Now skip the operator token we're on. // Now skip the operator token we're on.
leftOperand = new BinaryExpressionSyntax(contextFlags, leftOperand, consumeToken(operatorToken), leftOperand = new BinaryExpressionSyntax(contextFlags, leftOperand, consumeToken(operatorToken),
tryParseBinaryExpressionOrHigher(currentToken(), /*force:*/ true, newPrecedence)); parseBinaryExpressionOrHigher(currentToken(), newPrecedence));
} }
return leftOperand; return leftOperand;
@ -2850,7 +2835,7 @@ module TypeScript.Parser {
return token0; return token0;
} }
function tryParseMemberExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): IMemberExpressionSyntax { function parseMemberExpressionOrHigher(_currentToken: ISyntaxToken): IMemberExpressionSyntax {
// Note: to make our lives simpler, we decompose the the NewExpression productions and // Note: to make our lives simpler, we decompose the the NewExpression productions and
// place ObjectCreationExpression and FunctionExpression into PrimaryExpression. // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
// like so: // like so:
@ -2898,11 +2883,7 @@ module TypeScript.Parser {
// //
// Because CallExpression and MemberExpression are left recursive, we need to bottom out // Because CallExpression and MemberExpression are left recursive, we need to bottom out
// of the recursion immediately. So we parse out a primary expression to start with. // of the recursion immediately. So we parse out a primary expression to start with.
var expression: IMemberExpressionSyntax = tryParsePrimaryExpression(_currentToken, force); var expression = parsePrimaryExpression(_currentToken);
if (expression === undefined) {
return undefined;
}
return <IMemberExpressionSyntax>parseMemberExpressionRest(expression); return <IMemberExpressionSyntax>parseMemberExpressionRest(expression);
} }
@ -2960,7 +2941,7 @@ module TypeScript.Parser {
} }
} }
function tryParseLeftHandSideExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): ILeftHandSideExpressionSyntax { function parseLeftHandSideExpressionOrHigher(_currentToken: ISyntaxToken): ILeftHandSideExpressionSyntax {
// Original Ecma: // Original Ecma:
// LeftHandSideExpression: See 11.2 // LeftHandSideExpression: See 11.2
// NewExpression // NewExpression
@ -2992,16 +2973,9 @@ module TypeScript.Parser {
// completes the LeftHandSideExpression, or starts the beginning of the first four // completes the LeftHandSideExpression, or starts the beginning of the first four
// CallExpression productions. // CallExpression productions.
var expression: ILeftHandSideExpressionSyntax = undefined; var expression: ILeftHandSideExpressionSyntax = _currentToken.kind === SyntaxKind.SuperKeyword
if (_currentToken.kind === SyntaxKind.SuperKeyword) { ? parseSuperExpression(_currentToken)
expression = parseSuperExpression(_currentToken); : parseMemberExpressionOrHigher(_currentToken);
}
else {
expression = tryParseMemberExpressionOrHigher(_currentToken, force);
if (expression === undefined) {
return undefined;
}
}
// Now, we *may* be complete. However, we might have consumed the start of a // Now, we *may* be complete. However, we might have consumed the start of a
// CallExpression. As such, we need to consume the rest of it here to be complete. // CallExpression. As such, we need to consume the rest of it here to be complete.
@ -3019,11 +2993,8 @@ module TypeScript.Parser {
: new MemberAccessExpressionSyntax(contextFlags, expression, eatToken(SyntaxKind.DotToken), eatIdentifierNameToken()); : new MemberAccessExpressionSyntax(contextFlags, expression, eatToken(SyntaxKind.DotToken), eatIdentifierNameToken());
} }
function tryParsePostfixExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): IPostfixExpressionSyntax { function parsePostfixExpressionOrHigher(_currentToken: ISyntaxToken): IPostfixExpressionSyntax {
var expression = tryParseLeftHandSideExpressionOrHigher(_currentToken, force); var expression = parseLeftHandSideExpressionOrHigher(_currentToken);
if (expression === undefined) {
return undefined;
}
var _currentToken = currentToken(); var _currentToken = currentToken();
var currentTokenKind = _currentToken.kind; var currentTokenKind = _currentToken.kind;
@ -3124,7 +3095,7 @@ module TypeScript.Parser {
// cause a missing identiifer to be created), so that we will then consume the // cause a missing identiifer to be created), so that we will then consume the
// comma and the following list items). // comma and the following list items).
var force = currentToken().kind === SyntaxKind.CommaToken; var force = currentToken().kind === SyntaxKind.CommaToken;
return allowInAnd(force ? parseAssignmentExpressionOrHigher : tryParseAssignmentExpressionOrHigher); return (force || isExpression(currentToken())) ? allowInAnd(parseAssignmentExpressionOrHigher) : undefined;
} }
function parseElementAccessArgumentExpression(openBracketToken: ISyntaxToken) { function parseElementAccessArgumentExpression(openBracketToken: ISyntaxToken) {
@ -3141,20 +3112,7 @@ module TypeScript.Parser {
parseElementAccessArgumentExpression(openBracketToken), eatToken(SyntaxKind.CloseBracketToken)); parseElementAccessArgumentExpression(openBracketToken), eatToken(SyntaxKind.CloseBracketToken));
} }
function tryParsePrimaryExpression(_currentToken: ISyntaxToken, force: boolean): IPrimaryExpressionSyntax { function parsePrimaryExpression(_currentToken: ISyntaxToken): IPrimaryExpressionSyntax {
// Have to check for 'async function' first as 'async' is an identifier and will be
// consumed immediately below this.
if (_currentToken.kind === SyntaxKind.AsyncKeyword) {
var token1 = peekToken(1);
if (!token1.hasLeadingNewLine() && token1.kind === SyntaxKind.FunctionKeyword) {
return parseFunctionExpression();
}
}
if (isIdentifier(_currentToken)) {
return eatIdentifierToken();
}
var currentTokenKind = _currentToken.kind; var currentTokenKind = _currentToken.kind;
switch (currentTokenKind) { switch (currentTokenKind) {
case SyntaxKind.ThisKeyword: case SyntaxKind.ThisKeyword:
@ -3183,13 +3141,16 @@ module TypeScript.Parser {
// If we see a standalone / or /= and we're expecting an expression, then reparse // If we see a standalone / or /= and we're expecting an expression, then reparse
// it as a regular expression. // it as a regular expression.
return reparseDivideAsRegularExpression(); return reparseDivideAsRegularExpression();
case SyntaxKind.AsyncKeyword:
var token1 = peekToken(1);
if (!token1.hasLeadingNewLine() && token1.kind === SyntaxKind.FunctionKeyword) {
return parseFunctionExpression();
}
break;
} }
if (!force) { // Nothing else worked. try to eat an identifier. If we can't, we'll report an
return undefined; // appropriate error.
}
// Nothing else worked, report an error and produce a missing token.
return eatIdentifierToken(DiagnosticCode.Expression_expected); return eatIdentifierToken(DiagnosticCode.Expression_expected);
} }
@ -3216,15 +3177,15 @@ module TypeScript.Parser {
} }
function parseTypeOfExpression(typeOfKeyword: ISyntaxToken): TypeOfExpressionSyntax { function parseTypeOfExpression(typeOfKeyword: ISyntaxToken): TypeOfExpressionSyntax {
return new TypeOfExpressionSyntax(contextFlags, consumeToken(typeOfKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); return new TypeOfExpressionSyntax(contextFlags, consumeToken(typeOfKeyword), parseUnaryExpressionOrHigher(currentToken()));
} }
function parseDeleteExpression(deleteKeyword: ISyntaxToken): DeleteExpressionSyntax { function parseDeleteExpression(deleteKeyword: ISyntaxToken): DeleteExpressionSyntax {
return new DeleteExpressionSyntax(contextFlags, consumeToken(deleteKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); return new DeleteExpressionSyntax(contextFlags, consumeToken(deleteKeyword), parseUnaryExpressionOrHigher(currentToken()));
} }
function parseVoidExpression(voidKeyword: ISyntaxToken): VoidExpressionSyntax { function parseVoidExpression(voidKeyword: ISyntaxToken): VoidExpressionSyntax {
return new VoidExpressionSyntax(contextFlags, consumeToken(voidKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); return new VoidExpressionSyntax(contextFlags, consumeToken(voidKeyword), parseUnaryExpressionOrHigher(currentToken()));
} }
function parseFunctionExpression(): FunctionExpressionSyntax { function parseFunctionExpression(): FunctionExpressionSyntax {
@ -3271,7 +3232,7 @@ module TypeScript.Parser {
return new ObjectCreationExpressionSyntax(contextFlags, return new ObjectCreationExpressionSyntax(contextFlags,
consumeToken(newKeyword), consumeToken(newKeyword),
tryParseMemberExpressionOrHigher(currentToken(), /*force:*/ true), parseMemberExpressionOrHigher(currentToken()),
tryParseArgumentList()); tryParseArgumentList());
} }
@ -3317,7 +3278,10 @@ module TypeScript.Parser {
function parseCastExpression(lessThanToken: ISyntaxToken): CastExpressionSyntax { function parseCastExpression(lessThanToken: ISyntaxToken): CastExpressionSyntax {
return new CastExpressionSyntax(contextFlags, return new CastExpressionSyntax(contextFlags,
consumeToken(lessThanToken), parseType(), eatToken(SyntaxKind.GreaterThanToken), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); consumeToken(lessThanToken),
parseType(),
eatToken(SyntaxKind.GreaterThanToken),
parseUnaryExpressionOrHigher(currentToken()));
} }
function parseParenthesizedExpression(openParenToken: ISyntaxToken): ParenthesizedExpressionSyntax { function parseParenthesizedExpression(openParenToken: ISyntaxToken): ParenthesizedExpressionSyntax {
@ -4034,7 +3998,7 @@ module TypeScript.Parser {
// We do not want the > to be consumed as part of the "" expression. By starting // We do not want the > to be consumed as part of the "" expression. By starting
// at 'unary' expression and not 'binary' expression, we ensure that we don't accidently // at 'unary' expression and not 'binary' expression, we ensure that we don't accidently
// consume the >. // consume the >.
return tryParseUnaryExpressionOrHigher(_currentToken, /*force:*/ true); return parseUnaryExpressionOrHigher(_currentToken);
} }
return eatIdentifierToken(DiagnosticCode.Type_expected); return eatIdentifierToken(DiagnosticCode.Type_expected);