diff --git a/src/services/syntax/parser.ts b/src/services/syntax/parser.ts index ad32a43422d..8fe62590d0a 100644 --- a/src/services/syntax/parser.ts +++ b/src/services/syntax/parser.ts @@ -1986,7 +1986,17 @@ module TypeScript.Parser { consumeToken(switchKeyword); var openParenToken = eatToken(SyntaxKind.OpenParenToken); - var expression = parseExpression(/*allowIn:*/ true); + var expression: IExpressionSyntax; + + // if we have "switch {" + // then don't try to consume the { as the start of an expression. + if (openParenToken.fullWidth() === 0 && currentToken().kind === SyntaxKind.OpenBraceToken) { + expression = eatIdentifierToken(); + } + else { + expression = parseExpression(/*allowIn:*/ true); + } + var closeParenToken = eatToken(SyntaxKind.CloseParenToken); var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); @@ -3312,8 +3322,23 @@ module TypeScript.Parser { else if (isFunctionPropertyAssignment(inErrorRecovery)) { return parseFunctionPropertyAssignment(); } - else if (isSimplePropertyAssignment(inErrorRecovery)) { - return parseSimplePropertyAssignment(); + else if (isSimpleOrShorthandPropertyAssignment(inErrorRecovery)) { + var _currentToken = currentToken(); + if (isIdentifier(_currentToken) && peekToken(1).kind !== SyntaxKind.ColonToken) { + // To be a shorthand property assignment we must have an identifier (and not a + // keyword or literal) and it must not be followed by a colon. + return consumeToken(_currentToken); + } + else { + // If we didn't have an identifier, then we must have gotten a keyword or a + // literal. Neither of these are allowed in a shorthand property, so this must + // be a simple property assignment. + // + // Also, if we have an identifier and it is followed by a colon then this is + // definitely a simple property assignment. + return new SimplePropertyAssignmentSyntax(parseNodeData, + eatPropertyName(), eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true)); + } } else { return undefined; @@ -3323,7 +3348,7 @@ module TypeScript.Parser { function isPropertyAssignment(inErrorRecovery: boolean): boolean { return isAccessor(modifierCount(), inErrorRecovery) || isFunctionPropertyAssignment(inErrorRecovery) || - isSimplePropertyAssignment(inErrorRecovery); + isSimpleOrShorthandPropertyAssignment(inErrorRecovery); } function eatPropertyName(): ISyntaxToken { @@ -3344,15 +3369,10 @@ module TypeScript.Parser { parseBlock(/*parseBlockEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ true)); } - function isSimplePropertyAssignment(inErrorRecovery: boolean): boolean { + function isSimpleOrShorthandPropertyAssignment(inErrorRecovery: boolean): boolean { return isPropertyName(currentToken(), inErrorRecovery); } - function parseSimplePropertyAssignment(): SimplePropertyAssignmentSyntax { - return new SimplePropertyAssignmentSyntax(parseNodeData, - eatPropertyName(), eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true)); - } - function isPropertyName(token: ISyntaxToken, inErrorRecovery: boolean): boolean { // NOTE: we do *not* want to check "isIdentifier" here. Any IdentifierName is // allowed here, even reserved words like keywords. @@ -3372,6 +3392,10 @@ module TypeScript.Parser { } } + return isLiteralPropertyName(token); + } + + function isLiteralPropertyName(token: ISyntaxToken): boolean { // We allow a template literal while parser for error tolerance. We'll report errors // on this later in the grammar checker walker. var kind = token.kind; diff --git a/src/services/syntax/scanner.ts b/src/services/syntax/scanner.ts index 25c154ddd58..1f712c31651 100644 --- a/src/services/syntax/scanner.ts +++ b/src/services/syntax/scanner.ts @@ -219,7 +219,7 @@ module TypeScript.Scanner { } class FixedWidthTokenWithNoTrivia implements ISyntaxToken { - public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; public parent: ISyntaxElement; public childCount: number; @@ -254,7 +254,7 @@ module TypeScript.Scanner { FixedWidthTokenWithNoTrivia.prototype.childCount = 0; class LargeScannerToken implements ISyntaxToken { - public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; public parent: ISyntaxElement; public childCount: number; diff --git a/src/services/syntax/syntaxElement.ts b/src/services/syntax/syntaxElement.ts index 4d3ffc1d4c8..fcc68a4cad1 100644 --- a/src/services/syntax/syntaxElement.ts +++ b/src/services/syntax/syntaxElement.ts @@ -450,7 +450,7 @@ module TypeScript { _memberDeclarationBrand: any; } - export interface IPropertyAssignmentSyntax extends ISyntaxNode { + export interface IPropertyAssignmentSyntax extends ISyntaxNodeOrToken { _propertyAssignmentBrand: any; } diff --git a/src/services/syntax/syntaxToken.ts b/src/services/syntax/syntaxToken.ts index 57643fd6aac..63573169c74 100644 --- a/src/services/syntax/syntaxToken.ts +++ b/src/services/syntax/syntaxToken.ts @@ -1,7 +1,7 @@ /// module TypeScript { - export interface ISyntaxToken extends ISyntaxNodeOrToken, INameSyntax, IPrimaryExpressionSyntax { + export interface ISyntaxToken extends ISyntaxNodeOrToken, INameSyntax, IPrimaryExpressionSyntax, IPropertyAssignmentSyntax { // Adjusts the full start of this token. Should only be called by the parser. setFullStart(fullStart: number): void; @@ -304,7 +304,8 @@ module TypeScript.Syntax { } class EmptyToken implements ISyntaxToken { - public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; + public parent: ISyntaxElement; public childCount: number; @@ -418,7 +419,7 @@ module TypeScript.Syntax { EmptyToken.prototype.childCount = 0; class RealizedToken implements ISyntaxToken { - public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; private _fullStart: number; private _isKeywordConvertedToIdentifier: boolean; @@ -491,7 +492,7 @@ module TypeScript.Syntax { RealizedToken.prototype.childCount = 0; class ConvertedKeywordToken implements ISyntaxToken { - public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; public parent: ISyntaxElement; public kind: SyntaxKind;