diff --git a/src/services/syntax/constants.ts b/src/services/syntax/constants.ts index 13b3d8ad754..31b4e952824 100644 --- a/src/services/syntax/constants.ts +++ b/src/services/syntax/constants.ts @@ -15,12 +15,13 @@ module TypeScript { // only be used by the incremental parser if it is parsed in the same strict context as before. // last masks off the part of the int // - // The width of the node is stored in the remainder of the int. This allows us up to 512MB - // for a node by using all 29 bits. However, in the common case, we'll use less than 29 bits + // The width of the node is stored in the remainder of the int. This allows us up to 256MB + // for a node by using all 28 bits. However, in the common case, we'll use less than 28 bits // for the width. Thus, the info will be stored in a single int in chakra. NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001 NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010 NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100 - NodeFullWidthShift = 3, // 1111 1111 1111 1111 1111 1111 1111 1000 + NodeParsedInDisallowInMask = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000 + NodeFullWidthShift = 4, // 1111 1111 1111 1111 1111 1111 1111 0000 } } \ No newline at end of file diff --git a/src/services/syntax/parser.ts b/src/services/syntax/parser.ts index 878ee6c575a..4fe8a92c5d5 100644 --- a/src/services/syntax/parser.ts +++ b/src/services/syntax/parser.ts @@ -128,14 +128,6 @@ module TypeScript.Parser { // array. We may also, during speculative parsing, attach our skipped tokens to some // new token. When we rewind we need to restore whatever skipped tokens we started with. skippedTokens: ISyntaxToken[]; - - // isInStrictMode and listParsingState should not have to be tracked by a rewind point. - // Because they are naturally mutated and restored based on the normal stack movement of - // the parser, they should automatically return to whatever value they had to begin with - // if the parser decides to rewind or not. However, to ensure that this is true, we track - // these variables and check if they have the same value when we're rewinding/releasing. - isInStrictMode: boolean; - listParsingState: ListParsingState; } // Contains the actual logic to parse typescript/javascript. This is the code that generally @@ -162,7 +154,8 @@ module TypeScript.Parser { // TODO: do we need to store/restore this when speculative parsing? I don't think so. The // parsing logic already handles storing/restoring this and should work properly even if we're // speculative parsing. - var isInStrictMode: boolean = false; + var strictMode: boolean = false; + var disallowIn: boolean = false; // Current state of the parser. If we need to rewind we will store and reset these values as // appropriate. @@ -214,10 +207,6 @@ module TypeScript.Parser { rewindPoint.diagnosticsCount = diagnostics.length; rewindPoint.skippedTokens = _skippedTokens ? _skippedTokens.slice(0) : undefined; - // Values we keep around for debug asserting purposes. - rewindPoint.isInStrictMode = isInStrictMode; - rewindPoint.listParsingState = listParsingState; - return rewindPoint; } @@ -255,7 +244,7 @@ module TypeScript.Parser { // Note: we *can* reuse tokens when the strict mode changes. That's because tokens // are unaffected by strict mode. It's just the parser will decide what to do with it // differently depending on what mode it is in. - if (!node || parsedInStrictMode(node) !== isInStrictMode) { + if (!node || parsedInStrictMode(node) !== strictMode || parsedInDisallowInMode(node) !== disallowIn) { return undefined; } @@ -391,7 +380,7 @@ module TypeScript.Parser { if (tokenKind <= SyntaxKind.LastFutureReservedStrictKeyword) { // Could be a keyword or identifier. It's an identifier if we're not in strict // mode. - return !isInStrictMode; + return !strictMode; } // If it's typescript keyword, then it's actually a javascript identifier. @@ -575,16 +564,27 @@ module TypeScript.Parser { throw Errors.invalidOperation(); } - function setStrictMode(_isInStrictMode: boolean) { - isInStrictMode = _isInStrictMode; - parseNodeData = _isInStrictMode ? SyntaxConstants.NodeParsedInStrictModeMask : 0; + function updateParseNodeData() { + parseNodeData = + (strictMode ? SyntaxConstants.NodeParsedInStrictModeMask : 0) | + (disallowIn ? SyntaxConstants.NodeParsedInDisallowInMask : 0); + } + + function setStrictMode(val: boolean) { + strictMode = val; + updateParseNodeData(); + } + + function setDisallowIn(val: boolean) { + disallowIn = val; + updateParseNodeData(); } function parseSourceUnit(): SourceUnitSyntax { // Note: saving and restoring the 'isInStrictMode' state is not really necessary here // (as it will never be read afterwards). However, for symmetry with the rest of the // parsing code, we do the same here. - var savedIsInStrictMode = isInStrictMode + var savedIsInStrictMode = strictMode // Note: any skipped tokens produced after the end of all the module elements will be // added as skipped trivia to the start of the EOF token. @@ -611,7 +611,7 @@ module TypeScript.Parser { } function updateStrictModeState(items: any[]): void { - if (!isInStrictMode) { + if (!strictMode) { // Check if all the items are directive prologue elements. for (var i = 0, n = items.length; i < n; i++) { if (!isDirectivePrologueElement(items[i])) { @@ -890,8 +890,32 @@ module TypeScript.Parser { return isPropertyName(/*peekToken:*/ 0, inErrorRecovery); } + function allowInAnd(func: () => T): T { + if (disallowIn) { + setDisallowIn(false); + var result = func(); + setDisallowIn(true); + return result; + } + + // no need to do anything special if 'in' is already allowed. + return func(); + } + + function disallowInAnd(func: () => T): T { + if (disallowIn) { + // no need to do anything special if 'in' is already disallowed. + return func(); + } + + setDisallowIn(true); + var result = func(); + setDisallowIn(false); + return result; + } + function tryParseEnumElementEqualsValueClause(): EqualsValueClauseSyntax { - return isEqualsValueClause(/*inParameter*/ false) ? parseEqualsValueClause(/*allowIn:*/ true) : undefined; + return isEqualsValueClause(/*inParameter*/ false) ? allowInAnd(parseEqualsValueClause) : undefined; } function tryParseEnumElement(inErrorRecovery: boolean): EnumElementSyntax { @@ -1157,7 +1181,7 @@ module TypeScript.Parser { modifiers, new VariableDeclaratorSyntax(parseNodeData, propertyName, parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false), - isEqualsValueClause(/*inParameter*/ false) ? parseEqualsValueClause(/*allowIn:*/ true) : undefined), + isEqualsValueClause(/*inParameter*/ false) ? allowInAnd(parseEqualsValueClause) : undefined), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); } @@ -1613,13 +1637,16 @@ module TypeScript.Parser { } function parseDoStatement(doKeyword: ISyntaxToken): DoStatementSyntax { + // IterationStatement[Yield, Return] : + // do Statement[?Yield, ?Return]while (Expression[In, ?Yield]); opt + // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby // do;while(0)x will have a semicolon inserted before x. return new DoStatementSyntax(parseNodeData, consumeToken(doKeyword), parseStatement(/*inErrorRecovery:*/ false), eatToken(SyntaxKind.WhileKeyword), eatToken(SyntaxKind.OpenParenToken), - parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ true)); + allowInAnd(parseExpression), eatToken(SyntaxKind.CloseParenToken), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ true)); } function isLabeledStatement(currentToken: ISyntaxToken): boolean { @@ -1675,13 +1702,27 @@ module TypeScript.Parser { } function parseWithStatement(withKeyword: ISyntaxToken): WithStatementSyntax { + // WithStatement[Yield, Return] : + // with (Expression[In, ?Yield]) Statement[?Yield, ?Return] + return new WithStatementSyntax(parseNodeData, - consumeToken(withKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + consumeToken(withKeyword), + eatToken(SyntaxKind.OpenParenToken), + allowInAnd(parseExpression), + eatToken(SyntaxKind.CloseParenToken), + parseStatement(/*inErrorRecovery:*/ false)); } function parseWhileStatement(whileKeyword: ISyntaxToken): WhileStatementSyntax { + // IterationStatement[Yield, Return] : + // while (Expression[In, ?Yield]) Statement[?Yield, ?Return] + return new WhileStatementSyntax(parseNodeData, - consumeToken(whileKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + consumeToken(whileKeyword), + eatToken(SyntaxKind.OpenParenToken), + allowInAnd(parseExpression), + eatToken(SyntaxKind.CloseParenToken), + parseStatement(/*inErrorRecovery:*/ false)); } function isEmptyStatement(currentToken: ISyntaxToken, inErrorRecovery: boolean): boolean { @@ -1725,17 +1766,19 @@ module TypeScript.Parser { var initializer = tokenKind === SyntaxKind.SemicolonToken ? undefined : tokenKind === SyntaxKind.VarKeyword - ? parseVariableDeclaration(/*allowIn:*/ false) - : parseExpression(/*allowIn:*/ false); + ? disallowInAnd(parseVariableDeclaration) + : disallowInAnd(parseExpression) // In order to be a 'for-in' statement, we had to have an initializer of some sort, and // we had to actually get an 'in' keyword. if (initializer !== undefined && currentToken().kind === SyntaxKind.InKeyword) { - // for ( var VariableDeclarationNoIn in Expression ) Statement - // for ( LeftHandSideExpression in Expression ) Statement + // for ([lookahead not-in {let [ }] LeftHandSideExpression[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] + // for ( var ForBinding[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] + // for ( ForDeclaration[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] + return new ForInStatementSyntax(parseNodeData, forKeyword, openParenToken, initializer, eatToken(SyntaxKind.InKeyword), - parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + allowInAnd(parseExpression), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); } else { // NOTE: From the es5 section on Automatic Semicolon Insertion. @@ -1753,21 +1796,24 @@ module TypeScript.Parser { } function tryParseForStatementCondition(): IExpressionSyntax { + // for ( Expression[?Yield]opt ; Expression[In, ?Yield]opt ; Expression[In, ?Yield]opt ) + var tokenKind = currentToken().kind; if (tokenKind !== SyntaxKind.SemicolonToken && tokenKind !== SyntaxKind.CloseParenToken && tokenKind !== SyntaxKind.EndOfFileToken) { - return parseExpression(/*allowIn:*/ true); + return allowInAnd(parseExpression); } return undefined; } function tryParseForStatementIncrementor(): IExpressionSyntax { + // for ( Expression[?Yield]opt ; Expression[In, ?Yield]opt ; Expression[In, ?Yield]opt ) var tokenKind = currentToken().kind; if (tokenKind !== SyntaxKind.CloseParenToken && tokenKind !== SyntaxKind.EndOfFileToken) { - return parseExpression(/*allowIn:*/ true); + return allowInAnd(parseExpression); } return undefined; @@ -1797,9 +1843,12 @@ module TypeScript.Parser { } function parseSwitchExpression(openParenToken: ISyntaxToken) { + // SwitchStatement[Yield, Return] : + // switch (Expression[In, ?Yield] ) CaseBlock[?Yield, ?Return] + return openParenToken.fullWidth() === 0 && currentToken().kind === SyntaxKind.OpenBraceToken ? eatIdentifierToken() - : parseExpression(/*allowIn:*/ true); + : allowInAnd(parseExpression); } function parseSwitchStatement(switchKeyword: ISyntaxToken) { @@ -1849,10 +1898,12 @@ module TypeScript.Parser { function parseCaseSwitchClause(caseKeyword: ISyntaxToken): CaseSwitchClauseSyntax { // Debug.assert(isCaseSwitchClause()); + // CaseClause[Yield, Return] : + // case Expression[In, ?Yield] : StatementList[?Yield, ?Return]opt - return new CaseSwitchClauseSyntax(parseNodeData, + return new CaseSwitchClauseSyntax(parseNodeData, consumeToken(caseKeyword), - parseExpression(/*allowIn:*/ true), + allowInAnd(parseExpression), eatToken(SyntaxKind.ColonToken), parseSyntaxList(ListParsingState.SwitchClause_Statements)); } @@ -1867,12 +1918,15 @@ module TypeScript.Parser { } function parseThrowStatementExpression(): IExpressionSyntax { + // ThrowStatement[Yield] : + // throw [no LineTerminator here]Expression[In, ?Yield]; + // Because of automatic semicolon insertion, we need to report error if this // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' // directly as that might consume an expression on the following line. return canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) ? createMissingToken(SyntaxKind.IdentifierName, undefined) - : parseExpression(/*allowIn:*/ true); + : allowInAnd(parseExpression); } function parseThrowStatement(throwKeyword: ISyntaxToken): ThrowStatementSyntax { @@ -1881,7 +1935,10 @@ module TypeScript.Parser { } function tryParseReturnStatementExpression(): IExpressionSyntax { - return !canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) ? parseExpression(/*allowIn:*/ true) : undefined; + // ReturnStatement[Yield] : + // return [no LineTerminator here]Expression[In, ?Yield]; + + return !canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) ? allowInAnd(parseExpression) : undefined; } function parseReturnStatement(returnKeyword: ISyntaxToken): ReturnStatementSyntax { @@ -1903,11 +1960,14 @@ module TypeScript.Parser { function tryParseAssignmentOrOmittedExpression(): IExpressionSyntax { // Debug.assert(isAssignmentOrOmittedExpression()); + // ElementList[Yield] : + // Elisionopt AssignmentExpression[In, ?Yield] + if (currentToken().kind === SyntaxKind.CommaToken) { return new OmittedExpressionSyntax(parseNodeData); } - return tryParseAssignmentExpressionOrHigher(/*force:*/ false, /*allowIn:*/ true); + return allowInAnd(tryParseAssignmentExpressionOrHigher_NoForce); } function isExpression(currentToken: ISyntaxToken): boolean { @@ -1982,13 +2042,25 @@ module TypeScript.Parser { } function parseExpressionStatement(): ExpressionStatementSyntax { - return new ExpressionStatementSyntax(parseNodeData, parseExpression(/*allowIn:*/ true), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + // ExpressionStatement[Yield] : + // [lookahead not-in {{, function, class, let [ }] Expression[In, ?Yield]; + + return new ExpressionStatementSyntax(parseNodeData, + allowInAnd(parseExpression), + eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); } function parseIfStatement(ifKeyword: ISyntaxToken): IfStatementSyntax { + // IfStatement[Yield, Return] : + // if (Expression[In, ?Yield]) Statement[?Yield, ?Return] else Statement[?Yield, ?Return] + // if (Expression[In, ?Yield]) Statement[?Yield, ?Return] + return new IfStatementSyntax(parseNodeData, - consumeToken(ifKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), - eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false), parseOptionalElseClause()); + consumeToken(ifKeyword), + eatToken(SyntaxKind.OpenParenToken), + allowInAnd(parseExpression), + eatToken(SyntaxKind.CloseParenToken), + parseStatement(/*inErrorRecovery:*/ false), parseOptionalElseClause()); } function parseOptionalElseClause(): ElseClauseSyntax { @@ -2004,20 +2076,19 @@ module TypeScript.Parser { } function parseVariableStatement(): VariableStatementSyntax { + // VariableStatement[Yield] : + // var VariableDeclarationList[In, ?Yield]; + return new VariableStatementSyntax(parseNodeData, - parseModifiers(), parseVariableDeclaration(/*allowIn:*/ true), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + parseModifiers(), allowInAnd(parseVariableDeclaration), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); } - function parseVariableDeclaration(allowIn: boolean): VariableDeclarationSyntax { + function parseVariableDeclaration(): VariableDeclarationSyntax { // Debug.assert(currentToken().kind === SyntaxKind.VarKeyword); - var listParsingState = allowIn - ? ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn - : ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn; - return new VariableDeclarationSyntax(parseNodeData, eatToken(SyntaxKind.VarKeyword), - parseSeparatedSyntaxList(listParsingState)); + parseSeparatedSyntaxList(ListParsingState.VariableDeclaration_VariableDeclarators)); } function isVariableDeclarator(): boolean { @@ -2052,13 +2123,7 @@ module TypeScript.Parser { return variableDeclarator.equalsValueClause === undefined; } - function tryParseVariableDeclarator(allowIn: boolean): VariableDeclaratorSyntax { - // TODO(cyrusn): What if the 'allowIn' context has changed between when we last parsed - // and now? We could end up with an incorrect tree. For example, say we had in the old - // tree "var i = a in b". Then, in the new tree the declarator portion moved into: - // "for (var i = a in b". We would not want to reuse the declarator as the "in b" portion - // would need to be consumed by the for declaration instead. Need to see if it is possible - // to hit this case. + function tryParseVariableDeclarator(): VariableDeclaratorSyntax { var node = currentNode(); if (canReuseVariableDeclaratorNode(node)) { consumeNode(node); @@ -2077,7 +2142,7 @@ module TypeScript.Parser { typeAnnotation = parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false); if (isEqualsValueClause(/*inParameter*/ false)) { - equalsValueClause = parseEqualsValueClause(allowIn); + equalsValueClause = parseEqualsValueClause(); } } @@ -2121,17 +2186,20 @@ module TypeScript.Parser { return false; } - function parseEqualsValueClause(allowIn: boolean): EqualsValueClauseSyntax { + function parseEqualsValueClause(): EqualsValueClauseSyntax { + // Initializer[In, Yield] : + // = AssignmentExpression[?In, ?Yield] + return new EqualsValueClauseSyntax(parseNodeData, - eatToken(SyntaxKind.EqualsToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + eatToken(SyntaxKind.EqualsToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true)); } - function parseExpression(allowIn: boolean): IExpressionSyntax { + function parseExpression(): IExpressionSyntax { // Expression[in]: // AssignmentExpression[in] // Expression[in] , AssignmentExpression[in] - var leftOperand = tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn); + var leftOperand = tryParseAssignmentExpressionOrHigher(/*force:*/ true); while (true) { var _currentToken = currentToken(); if (_currentToken.kind !== SyntaxKind.CommaToken) { @@ -2139,17 +2207,25 @@ module TypeScript.Parser { } leftOperand = new BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(_currentToken), - tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + tryParseAssignmentExpressionOrHigher(/*force:*/ true)); } return leftOperand; } + function tryParseAssignmentExpressionOrHigher_NoForce(): IExpressionSyntax { + return tryParseAssignmentExpressionOrHigher(/*force:*/ false); + } + + function tryParseAssignmentExpressionOrHigher_Force(): IExpressionSyntax { + return tryParseAssignmentExpressionOrHigher(/*force:*/ true); + } + // 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 // precedence than 'comma'. Otherwise we'll get: "var a = (1, (b = 2))", instead of // "var a = (1), b = (2)"); - function tryParseAssignmentExpressionOrHigher(force: boolean, allowIn: boolean): IExpressionSyntax { + function tryParseAssignmentExpressionOrHigher(force: boolean): IExpressionSyntax { // Augmented by TypeScript: // // AssignmentExpression[in]: @@ -2190,7 +2266,7 @@ module TypeScript.Parser { // 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 // and consumes anything. - var leftOperand = tryParseBinaryExpressionOrHigher(_currentToken, force, BinaryExpressionPrecedence.Lowest, allowIn); + var leftOperand = tryParseBinaryExpressionOrHigher(_currentToken, force, BinaryExpressionPrecedence.Lowest); if (leftOperand === undefined) { return undefined; } @@ -2203,12 +2279,12 @@ module TypeScript.Parser { // Check for recursive assignment expressions. if (SyntaxFacts.isAssignmentOperatorToken(operatorToken.kind)) { return new BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(operatorToken), - tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + tryParseAssignmentExpressionOrHigher(/*force:*/ true)); } } // It wasn't an assignment or a lambda. This is a conditional expression: - return parseConditionalExpressionRest(allowIn, leftOperand); + return parseConditionalExpressionRest(leftOperand); } function tryParseAnyArrowFunctionExpression(_currentToken: ISyntaxToken): IExpressionSyntax { @@ -2237,7 +2313,7 @@ module TypeScript.Parser { } } - function tryParseBinaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean, precedence: BinaryExpressionPrecedence, allowIn: boolean): IExpressionSyntax { + function tryParseBinaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean, precedence: BinaryExpressionPrecedence): IExpressionSyntax { // The binary expressions are incredibly left recursive in their definitions. We // 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 @@ -2251,10 +2327,10 @@ module TypeScript.Parser { } // We then pop up the stack consuming the other side of the binary exprssion if it exists. - return parseBinaryExpressionRest(precedence, allowIn, leftOperand); + return parseBinaryExpressionRest(precedence, leftOperand); } - function parseConditionalExpressionRest(allowIn: boolean, leftOperand: IExpressionSyntax): IExpressionSyntax { + function parseConditionalExpressionRest(leftOperand: IExpressionSyntax): IExpressionSyntax { // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. var _currentToken = currentToken(); @@ -2268,11 +2344,11 @@ module TypeScript.Parser { // allowed in the 'true' part of a conditional expression. return new ConditionalExpressionSyntax(parseNodeData, - leftOperand, consumeToken(_currentToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true), - eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + leftOperand, consumeToken(_currentToken), allowInAnd(tryParseAssignmentExpressionOrHigher_Force), + eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true)); } - function parseBinaryExpressionRest(precedence: BinaryExpressionPrecedence, allowIn: boolean, leftOperand: IExpressionSyntax): IExpressionSyntax { + function parseBinaryExpressionRest(precedence: BinaryExpressionPrecedence, leftOperand: IExpressionSyntax): IExpressionSyntax { while (true) { // We either have a binary operator here, or we're finished. We call // currentOperatorToken versus currentToken here so that we merge token sequences @@ -2291,7 +2367,7 @@ module TypeScript.Parser { } // also, if it's the 'in' operator, only allow if our caller allows it. - if (tokenKind === SyntaxKind.InKeyword && !allowIn) { + if (tokenKind === SyntaxKind.InKeyword && disallowIn) { break; } @@ -2309,7 +2385,7 @@ module TypeScript.Parser { // Now skip the operator token we're on. leftOperand = new BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(operatorToken), - tryParseBinaryExpressionOrHigher(currentToken(), /*force:*/ true, newPrecedence, allowIn)); + tryParseBinaryExpressionOrHigher(currentToken(), /*force:*/ true, newPrecedence)); } return leftOperand; @@ -2608,18 +2684,23 @@ module TypeScript.Parser { } function tryParseArgumentListExpression(): IExpressionSyntax { + // ArgumentList[Yield] : + // AssignmentExpression[In, ?Yield] + // Generally while parsing lists, we don't want to 'force' the parser to parse - // the item. That way, if the expected item isn't htere, we can bail out and + // the item. That way, if the expected item isn't there, we can bail out and // move to a higher stage of list parsing. However, it's extremely common to // see something like "Foo(, a". in this case, even though there isn't an expression // after the open paren, we still want to force parsing an expression (which will // cause a missing identiifer to be created), so that we will then consume the // comma and the following list items). var force = currentToken().kind === SyntaxKind.CommaToken; - return tryParseAssignmentExpressionOrHigher(force, /*allowIn:*/ true); + return allowInAnd(force ? tryParseAssignmentExpressionOrHigher_Force : tryParseAssignmentExpressionOrHigher_NoForce); } function parseElementAccessArgumentExpression(openBracketToken: ISyntaxToken, inObjectCreation: boolean) { + // MemberExpression[?Yield] [ Expression[In, ?Yield] ] + // It's not uncommon for a user to write: "new Type[]". Check for that common pattern // and report a better error message. if (inObjectCreation && currentToken().kind === SyntaxKind.CloseBracketToken) { @@ -2632,7 +2713,7 @@ module TypeScript.Parser { return Syntax.emptyToken(SyntaxKind.IdentifierName); } else { - return parseExpression(/*allowIn:*/ true); + return allowInAnd(parseExpression); } } @@ -2773,7 +2854,12 @@ module TypeScript.Parser { } function parseTemplateClause(): TemplateClauseSyntax { - var expression = parseExpression(/*allowIn:*/ true); + // TemplateLiteral[Yield] : See 12.2.8 + // NoSubstitutionTemplate + // TemplateHead Expression[In, ?Yield] + // [Lexical goal InputElementTemplateTail] TemplateSpans[?Yield] + + var expression = allowInAnd(parseExpression); var token = currentToken(); if (token.kind === SyntaxKind.CloseBraceToken) { @@ -2796,8 +2882,12 @@ module TypeScript.Parser { } function parseParenthesizedExpression(openParenToken: ISyntaxToken): ParenthesizedExpressionSyntax { + // ( Expression[In, ?Yield] ) + return new ParenthesizedExpressionSyntax(parseNodeData, - consumeToken(openParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken)); + consumeToken(openParenToken), + allowInAnd(parseExpression), + eatToken(SyntaxKind.CloseParenToken)); } function tryParseParenthesizedArrowFunctionExpression(): ParenthesizedArrowFunctionExpressionSyntax { @@ -2856,41 +2946,34 @@ module TypeScript.Parser { } function parseArrowFunctionBody(): BlockSyntax | IExpressionSyntax { - var block = tryParseArrowFunctionBlock(); - if (block !== undefined) { - return block; - } + // ConciseBody[In] : + // [lookahead not in {] AssignmentExpression[?In] + // { FunctionBody } - return tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true); - } - - function tryParseArrowFunctionBlock(): BlockSyntax { if (isBlock()) { return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false); } - else { - // We didn't have a block. However, we may be in an error situation. For example, - // if the user wrote: - // - // a => - // var v = 0; - // } - // - // (i.e. they're missing the open brace). See if that's the case so we can try to - // recover better. If we don't do this, then the next close curly we see may end - // up preemptively closing the containing construct. - var _modifierCount = modifierCount(); - if (isStatement(_modifierCount, /*inErrorRecovery:*/ false) && - !isExpressionStatement(currentToken()) && - !isFunctionDeclaration(_modifierCount)) { - // We've seen a statement (and it isn't an expressionStatement like 'foo()'), - // so treat this like a block with a missing open brace. - return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ true, /*checkForStrictMode:*/ false); - } - else { - return undefined; - } + + // We didn't have a block. However, we may be in an error situation. For example, + // if the user wrote: + // + // a => + // var v = 0; + // } + // + // (i.e. they're missing the open brace). See if that's the case so we can try to + // recover better. If we don't do this, then the next close curly we see may end + // up preemptively closing the containing construct. + var _modifierCount = modifierCount(); + if (isStatement(_modifierCount, /*inErrorRecovery:*/ false) && + !isExpressionStatement(currentToken()) && + !isFunctionDeclaration(_modifierCount)) { + // We've seen a statement (and it isn't an expressionStatement like 'foo()'), + // so treat this like a block with a missing open brace. + return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ true, /*checkForStrictMode:*/ false); } + + return tryParseAssignmentExpressionOrHigher(/*force:*/ true); } function isSimpleArrowFunctionExpression(_currentToken: ISyntaxToken): boolean { @@ -3126,6 +3209,8 @@ module TypeScript.Parser { return parseFunctionPropertyAssignment(propertyName); } else { + // PropertyName[?Yield] : AssignmentExpression[In, ?Yield] + // 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. @@ -3133,7 +3218,7 @@ module TypeScript.Parser { // 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, - propertyName, eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true)); + propertyName, eatToken(SyntaxKind.ColonToken), allowInAnd(tryParseAssignmentExpressionOrHigher_Force)); } } @@ -3201,8 +3286,13 @@ module TypeScript.Parser { } function parseComputedPropertyName(openBracketToken: ISyntaxToken): ComputedPropertyNameSyntax { + // ComputedPropertyName[Yield] : + // [AssignmentExpression[In, ?Yield]] + return new ComputedPropertyNameSyntax(parseNodeData, - consumeToken(openBracketToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true), eatToken(SyntaxKind.CloseBracketToken)); + consumeToken(openBracketToken), + allowInAnd(tryParseAssignmentExpressionOrHigher_Force), + eatToken(SyntaxKind.CloseBracketToken)); } function parseFunctionPropertyAssignment(propertyName: IPropertyNameSyntax): FunctionPropertyAssignmentSyntax { @@ -3224,7 +3314,7 @@ module TypeScript.Parser { var statements: IStatementSyntax[]; if (parseBlockEvenWithNoOpenBrace || openBraceToken.fullWidth() > 0) { - var savedIsInStrictMode = isInStrictMode; + var savedIsInStrictMode = strictMode; var processItems = checkForStrictMode ? updateStrictModeState : undefined; var statements = parseSyntaxList(ListParsingState.Block_Statements, processItems); @@ -3606,7 +3696,7 @@ module TypeScript.Parser { var equalsValueClause: EqualsValueClauseSyntax = undefined; if (isEqualsValueClause(/*inParameter*/ true)) { - equalsValueClause = parseEqualsValueClause(/*allowIn:*/ true); + equalsValueClause = parseEqualsValueClause(); } return new ParameterSyntax(parseNodeData, dotDotDotToken, modifiers, identifier, questionToken, typeAnnotation, equalsValueClause); @@ -3865,8 +3955,7 @@ module TypeScript.Parser { case ListParsingState.ObjectType_TypeMembers: return isExpectedObjectType_TypeMembersTerminator(); case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return isExpectedClassOrInterfaceDeclaration_HeritageClausesTerminator(); case ListParsingState.HeritageClause_TypeNameList: return isExpectedHeritageClause_TypeNameListTerminator(); - case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return isExpectedVariableDeclaration_VariableDeclarators_AllowInTerminator(); - case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return isExpectedVariableDeclaration_VariableDeclarators_DisallowInTerminator(); + case ListParsingState.VariableDeclaration_VariableDeclarators: return isExpectedVariableDeclaration_VariableDeclaratorsTerminator(); case ListParsingState.ArgumentList_AssignmentExpressions: return isExpectedArgumentList_AssignmentExpressionsTerminator(); case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return isExpectedObjectLiteralExpression_PropertyAssignmentsTerminator(); case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return isExpectedLiteralExpression_AssignmentExpressionsTerminator(); @@ -3986,35 +4075,36 @@ module TypeScript.Parser { return false; } - function isExpectedVariableDeclaration_VariableDeclarators_DisallowInTerminator(): boolean { - // This is the case when we're parsing variable declarations in a for/for-in statement. - var tokenKind = currentToken().kind; + function isExpectedVariableDeclaration_VariableDeclaratorsTerminator(): boolean { + if (disallowIn) { + // This is the case when we're parsing variable declarations in a for/for-in statement. + var tokenKind = currentToken().kind; - if (tokenKind === SyntaxKind.SemicolonToken || - tokenKind === SyntaxKind.CloseParenToken) { - return true; + if (tokenKind === SyntaxKind.SemicolonToken || + tokenKind === SyntaxKind.CloseParenToken) { + return true; + } + + if (tokenKind === SyntaxKind.InKeyword) { + return true; + } + + return false; } + else { + //// This is the case when we're parsing variable declarations in a variable statement. - if (tokenKind === SyntaxKind.InKeyword) { - return true; + // ERROR RECOVERY TWEAK: + // For better error recovery, if we see a => then we just stop immediately. We've got an + // arrow function here and it's going to be very unlikely that we'll resynchronize and get + // another variable declaration. + if (currentToken().kind === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + // We're done when we can eat a semicolon. + return canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); } - - return false; - } - - function isExpectedVariableDeclaration_VariableDeclarators_AllowInTerminator(): boolean { - //// This is the case when we're parsing variable declarations in a variable statement. - - // ERROR RECOVERY TWEAK: - // For better error recovery, if we see a => then we just stop immediately. We've got an - // arrow function here and it's going to be very unlikely that we'll resynchronize and get - // another variable declaration. - if (currentToken().kind === SyntaxKind.EqualsGreaterThanToken) { - return true; - } - - // We're done when we can eat a semicolon. - return canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); } function isExpectedClassOrInterfaceDeclaration_HeritageClausesTerminator(): boolean { @@ -4085,22 +4175,21 @@ module TypeScript.Parser { // used so we can abort out of the try block if we see a 'catch' or 'finally' // keyword. There are no additional list items that they add, so we just // return 'false' here. - case ListParsingState.TryBlock_Statements: return false; - case ListParsingState.CatchBlock_Statements: return false; - case ListParsingState.EnumDeclaration_EnumElements: return isEnumElement(inErrorRecovery); - case ListParsingState.ObjectType_TypeMembers: return isTypeMember(inErrorRecovery); - case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return isHeritageClause(); - case ListParsingState.HeritageClause_TypeNameList: return isHeritageClauseTypeName(); - case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return isVariableDeclarator(); - case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return isVariableDeclarator(); - case ListParsingState.ArgumentList_AssignmentExpressions: return isExpectedArgumentList_AssignmentExpression(); - case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return isPropertyAssignment(inErrorRecovery); - case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return isAssignmentOrOmittedExpression(); - case ListParsingState.ParameterList_Parameters: return isParameter(); - case ListParsingState.IndexSignature_Parameters: return isParameter(); - case ListParsingState.TypeArgumentList_Types: return isType(); - case ListParsingState.TypeParameterList_TypeParameters: return isTypeParameter(); - case ListParsingState.TupleType_Types: return isType(); + case ListParsingState.TryBlock_Statements: return false; + case ListParsingState.CatchBlock_Statements: return false; + case ListParsingState.EnumDeclaration_EnumElements: return isEnumElement(inErrorRecovery); + case ListParsingState.ObjectType_TypeMembers: return isTypeMember(inErrorRecovery); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return isHeritageClause(); + case ListParsingState.HeritageClause_TypeNameList: return isHeritageClauseTypeName(); + case ListParsingState.VariableDeclaration_VariableDeclarators: return isVariableDeclarator(); + case ListParsingState.ArgumentList_AssignmentExpressions: return isExpectedArgumentList_AssignmentExpression(); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return isPropertyAssignment(inErrorRecovery); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return isAssignmentOrOmittedExpression(); + case ListParsingState.ParameterList_Parameters: return isParameter(); + case ListParsingState.IndexSignature_Parameters: return isParameter(); + case ListParsingState.TypeArgumentList_Types: return isType(); + case ListParsingState.TypeParameterList_TypeParameters: return isTypeParameter(); + case ListParsingState.TupleType_Types: return isType(); default: throw Errors.invalidOperation(); } } @@ -4123,55 +4212,53 @@ module TypeScript.Parser { function tryParseExpectedListItemWorker(currentListType: ListParsingState, inErrorRecovery: boolean): ISyntaxNodeOrToken { switch (currentListType) { - case ListParsingState.SourceUnit_ModuleElements: return tryParseModuleElement(inErrorRecovery); - case ListParsingState.ClassDeclaration_ClassElements: return tryParseClassElement(inErrorRecovery); - case ListParsingState.ModuleDeclaration_ModuleElements: return tryParseModuleElement(inErrorRecovery); - case ListParsingState.SwitchStatement_SwitchClauses: return tryParseSwitchClause(); - case ListParsingState.SwitchClause_Statements: return tryParseStatement(inErrorRecovery); - case ListParsingState.Block_Statements: return tryParseStatement(inErrorRecovery); - case ListParsingState.TryBlock_Statements: return tryParseStatement(inErrorRecovery); - case ListParsingState.CatchBlock_Statements: return tryParseStatement(inErrorRecovery); - case ListParsingState.EnumDeclaration_EnumElements: return tryParseEnumElement(inErrorRecovery); - case ListParsingState.ObjectType_TypeMembers: return tryParseTypeMember(inErrorRecovery); - case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return tryParseHeritageClause(); - case ListParsingState.HeritageClause_TypeNameList: return tryParseHeritageClauseTypeName(); - case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return tryParseVariableDeclarator(/*allowIn:*/ true); - case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return tryParseVariableDeclarator(/*allowIn:*/ false); - case ListParsingState.ArgumentList_AssignmentExpressions: return tryParseArgumentListExpression(); - case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return tryParsePropertyAssignment(inErrorRecovery); - case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return tryParseAssignmentOrOmittedExpression(); - case ListParsingState.ParameterList_Parameters: return tryParseParameter(); - case ListParsingState.IndexSignature_Parameters: return tryParseParameter(); - case ListParsingState.TypeArgumentList_Types: return tryParseType(); - case ListParsingState.TypeParameterList_TypeParameters: return tryParseTypeParameter(); - case ListParsingState.TupleType_Types: return tryParseType(); + case ListParsingState.SourceUnit_ModuleElements: return tryParseModuleElement(inErrorRecovery); + case ListParsingState.ClassDeclaration_ClassElements: return tryParseClassElement(inErrorRecovery); + case ListParsingState.ModuleDeclaration_ModuleElements: return tryParseModuleElement(inErrorRecovery); + case ListParsingState.SwitchStatement_SwitchClauses: return tryParseSwitchClause(); + case ListParsingState.SwitchClause_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.Block_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.TryBlock_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.CatchBlock_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.EnumDeclaration_EnumElements: return tryParseEnumElement(inErrorRecovery); + case ListParsingState.ObjectType_TypeMembers: return tryParseTypeMember(inErrorRecovery); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return tryParseHeritageClause(); + case ListParsingState.HeritageClause_TypeNameList: return tryParseHeritageClauseTypeName(); + case ListParsingState.VariableDeclaration_VariableDeclarators: return tryParseVariableDeclarator(); + case ListParsingState.ArgumentList_AssignmentExpressions: return tryParseArgumentListExpression(); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return tryParsePropertyAssignment(inErrorRecovery); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return tryParseAssignmentOrOmittedExpression(); + case ListParsingState.ParameterList_Parameters: return tryParseParameter(); + case ListParsingState.IndexSignature_Parameters: return tryParseParameter(); + case ListParsingState.TypeArgumentList_Types: return tryParseType(); + case ListParsingState.TypeParameterList_TypeParameters: return tryParseTypeParameter(); + case ListParsingState.TupleType_Types: return tryParseType(); default: throw Errors.invalidOperation(); } } function getExpectedListElementType(currentListType: ListParsingState): string { switch (currentListType) { - case ListParsingState.SourceUnit_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, undefined); - case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return '{'; - case ListParsingState.ClassDeclaration_ClassElements: return getLocalizedText(DiagnosticCode.constructor_function_accessor_or_variable, undefined); - case ListParsingState.ModuleDeclaration_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, undefined); - case ListParsingState.SwitchStatement_SwitchClauses: return getLocalizedText(DiagnosticCode.case_or_default_clause, undefined); - case ListParsingState.SwitchClause_Statements: return getLocalizedText(DiagnosticCode.statement, undefined); - case ListParsingState.Block_Statements: return getLocalizedText(DiagnosticCode.statement, undefined); - case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return getLocalizedText(DiagnosticCode.identifier, undefined); - case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return getLocalizedText(DiagnosticCode.identifier, undefined); - case ListParsingState.EnumDeclaration_EnumElements: return getLocalizedText(DiagnosticCode.identifier, undefined); - case ListParsingState.ObjectType_TypeMembers: return getLocalizedText(DiagnosticCode.call_construct_index_property_or_function_signature, undefined); - case ListParsingState.ArgumentList_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, undefined); - case ListParsingState.HeritageClause_TypeNameList: return getLocalizedText(DiagnosticCode.type_name, undefined); - case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return getLocalizedText(DiagnosticCode.property_or_accessor, undefined); - case ListParsingState.ParameterList_Parameters: return getLocalizedText(DiagnosticCode.parameter, undefined); - case ListParsingState.IndexSignature_Parameters: return getLocalizedText(DiagnosticCode.parameter, undefined); - case ListParsingState.TypeArgumentList_Types: return getLocalizedText(DiagnosticCode.type, undefined); - case ListParsingState.TypeParameterList_TypeParameters: return getLocalizedText(DiagnosticCode.type_parameter, undefined); - case ListParsingState.TupleType_Types: return getLocalizedText(DiagnosticCode.type, undefined); - case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, undefined); - default: throw Errors.invalidOperation(); + case ListParsingState.SourceUnit_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, undefined); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return '{'; + case ListParsingState.ClassDeclaration_ClassElements: return getLocalizedText(DiagnosticCode.constructor_function_accessor_or_variable, undefined); + case ListParsingState.ModuleDeclaration_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, undefined); + case ListParsingState.SwitchStatement_SwitchClauses: return getLocalizedText(DiagnosticCode.case_or_default_clause, undefined); + case ListParsingState.SwitchClause_Statements: return getLocalizedText(DiagnosticCode.statement, undefined); + case ListParsingState.Block_Statements: return getLocalizedText(DiagnosticCode.statement, undefined); + case ListParsingState.VariableDeclaration_VariableDeclarators: return getLocalizedText(DiagnosticCode.identifier, undefined); + case ListParsingState.EnumDeclaration_EnumElements: return getLocalizedText(DiagnosticCode.identifier, undefined); + case ListParsingState.ObjectType_TypeMembers: return getLocalizedText(DiagnosticCode.call_construct_index_property_or_function_signature, undefined); + case ListParsingState.ArgumentList_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, undefined); + case ListParsingState.HeritageClause_TypeNameList: return getLocalizedText(DiagnosticCode.type_name, undefined); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return getLocalizedText(DiagnosticCode.property_or_accessor, undefined); + case ListParsingState.ParameterList_Parameters: return getLocalizedText(DiagnosticCode.parameter, undefined); + case ListParsingState.IndexSignature_Parameters: return getLocalizedText(DiagnosticCode.parameter, undefined); + case ListParsingState.TypeArgumentList_Types: return getLocalizedText(DiagnosticCode.type, undefined); + case ListParsingState.TypeParameterList_TypeParameters: return getLocalizedText(DiagnosticCode.type_parameter, undefined); + case ListParsingState.TupleType_Types: return getLocalizedText(DiagnosticCode.type, undefined); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, undefined); + default: throw Errors.invalidOperation(); } } @@ -4271,33 +4358,35 @@ module TypeScript.Parser { // consume the token and add it to our list of 'skipped tokens'. We will then repeat the // above algorithm until we resynchronize at some point. enum ListParsingState { - SourceUnit_ModuleElements = 0, - ClassDeclaration_ClassElements = 1, - ModuleDeclaration_ModuleElements = 2, - SwitchStatement_SwitchClauses = 3, - SwitchClause_Statements = 4, - Block_Statements = 5, - TryBlock_Statements = 6, - CatchBlock_Statements = 7, - EnumDeclaration_EnumElements = 8, - ObjectType_TypeMembers = 9, - ClassOrInterfaceDeclaration_HeritageClauses = 10, - HeritageClause_TypeNameList = 11, - VariableDeclaration_VariableDeclarators_AllowIn = 12, - VariableDeclaration_VariableDeclarators_DisallowIn = 13, - ArgumentList_AssignmentExpressions = 14, - ObjectLiteralExpression_PropertyAssignments = 15, - ArrayLiteralExpression_AssignmentExpressions = 16, - ParameterList_Parameters = 17, - IndexSignature_Parameters = 18, - TypeArgumentList_Types = 19, - TypeParameterList_TypeParameters = 20, - TupleType_Types = 21, + SourceUnit_ModuleElements, + ClassDeclaration_ClassElements, + ModuleDeclaration_ModuleElements, + SwitchStatement_SwitchClauses, + SwitchClause_Statements, + Block_Statements, + TryBlock_Statements, + CatchBlock_Statements, + EnumDeclaration_EnumElements, + ObjectType_TypeMembers, + ClassOrInterfaceDeclaration_HeritageClauses, + HeritageClause_TypeNameList, + VariableDeclaration_VariableDeclarators, + ArgumentList_AssignmentExpressions, + ObjectLiteralExpression_PropertyAssignments, + ArrayLiteralExpression_AssignmentExpressions, + ParameterList_Parameters, + IndexSignature_Parameters, + TypeArgumentList_Types, + TypeParameterList_TypeParameters, + TupleType_Types, FirstListParsingState = SourceUnit_ModuleElements, LastListParsingState = TupleType_Types, } + // We use this enum to set bits. So make sure we have enough bits available. + Debug.assert(ListParsingState.LastListParsingState <= 30); + // We keep the parser around as a singleton. This is because calling createParser is actually // expensive in V8 currently. We then clear it after a parse so that it doesn't keep state // alive unintentionally. diff --git a/src/services/syntax/syntaxElement.ts b/src/services/syntax/syntaxElement.ts index 349f3110d63..6e05cb89587 100644 --- a/src/services/syntax/syntaxElement.ts +++ b/src/services/syntax/syntaxElement.ts @@ -26,6 +26,15 @@ module TypeScript { return (info & SyntaxConstants.NodeParsedInStrictModeMask) !== 0; } + export function parsedInDisallowInMode(node: ISyntaxNode): boolean { + var info = node.__data; + if (info === undefined) { + return false; + } + + return (info & SyntaxConstants.NodeParsedInDisallowInMask) !== 0; + } + export function previousToken(token: ISyntaxToken): ISyntaxToken { var start = token.fullStart(); if (start === 0) {