mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Attach skipped tokens to the following token, not the preceding one.
This makes handling skipped tokens much simpler, and helps put us in a position where tokens only have leading trivia and never trailing trivia.
This commit is contained in:
@@ -529,6 +529,8 @@ module TypeScript.IncrementalParser {
|
||||
}
|
||||
|
||||
function consumeToken(currentToken: ISyntaxToken): void {
|
||||
// Debug.assert(currentToken.fullWidth() > 0 || currentToken.kind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
// This token may have come from the old source unit, or from the new text. Handle
|
||||
// both accordingly.
|
||||
|
||||
|
||||
@@ -116,27 +116,6 @@ module TypeScript.Parser {
|
||||
export interface IRewindPoint {
|
||||
}
|
||||
|
||||
var arrayPool: any[][] = [];
|
||||
var arrayPoolCount: number = 0;
|
||||
|
||||
function getArray(): any[] {
|
||||
if (arrayPoolCount === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
arrayPoolCount--;
|
||||
var result = arrayPool[arrayPoolCount];
|
||||
arrayPool[arrayPoolCount] = undefined;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function returnArray(array: any[]) {
|
||||
array.length = 0;
|
||||
arrayPool[arrayPoolCount] = array;
|
||||
arrayPoolCount++;
|
||||
}
|
||||
|
||||
interface IParserRewindPoint extends IRewindPoint {
|
||||
// As we speculatively parse, we may build up diagnostics. When we rewind we want to
|
||||
// 'forget' that information.In order to do that we store the count of diagnostics and
|
||||
@@ -144,6 +123,12 @@ module TypeScript.Parser {
|
||||
// speculative parse does not affect any further results.
|
||||
diagnosticsCount: number;
|
||||
|
||||
// As we speculatively parse we may end up adding additional skipped tokens to the
|
||||
// _skippedTokens array in the parser. When we rewind we don't want those items in the
|
||||
// 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
|
||||
@@ -190,6 +175,8 @@ module TypeScript.Parser {
|
||||
|
||||
var parseNodeData: number = 0;
|
||||
|
||||
var _skippedTokens: ISyntaxToken[] = undefined;
|
||||
|
||||
function parseSyntaxTree(_source: IParserSource, isDeclaration: boolean): SyntaxTree {
|
||||
// First, set up our state.
|
||||
fileName = _source.fileName;
|
||||
@@ -222,7 +209,10 @@ module TypeScript.Parser {
|
||||
function getRewindPoint(): IParserRewindPoint {
|
||||
var rewindPoint = <IParserRewindPoint>source.getRewindPoint();
|
||||
|
||||
// See the comments in IParserRewindPoint for the explanation on why we need to store
|
||||
// this data, and what it is used for.
|
||||
rewindPoint.diagnosticsCount = diagnostics.length;
|
||||
rewindPoint.skippedTokens = _skippedTokens ? _skippedTokens.slice(0) : undefined;
|
||||
|
||||
// Values we keep around for debug asserting purposes.
|
||||
rewindPoint.isInStrictMode = isInStrictMode;
|
||||
@@ -235,6 +225,7 @@ module TypeScript.Parser {
|
||||
source.rewind(rewindPoint);
|
||||
|
||||
diagnostics.length = rewindPoint.diagnosticsCount;
|
||||
_skippedTokens = rewindPoint.skippedTokens;
|
||||
}
|
||||
|
||||
function releaseRewindPoint(rewindPoint: IParserRewindPoint): void {
|
||||
@@ -245,6 +236,14 @@ module TypeScript.Parser {
|
||||
}
|
||||
|
||||
function currentNode(): ISyntaxNode {
|
||||
// If we have any outstanding tokens, then don't reuse a node.
|
||||
// TODO(cyrusn): This may be too conservative. Perhaps we could reuse hte node and
|
||||
// attach the skipped tokens in front? For now though, being conservative is nice and
|
||||
// safe, and likely won't ever affect perf.
|
||||
if (_skippedTokens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var node = source.currentNode();
|
||||
|
||||
// We can only reuse a node if it was parsed under the same strict mode that we're
|
||||
@@ -277,12 +276,82 @@ module TypeScript.Parser {
|
||||
return source.peekToken(n);
|
||||
}
|
||||
|
||||
function skipToken(token: ISyntaxToken): void {
|
||||
_skippedTokens = _skippedTokens || [];
|
||||
_skippedTokens.push(token);
|
||||
|
||||
// directly tell the source to just consume the token we're skipping. i.e. do not
|
||||
// call 'consumeToken'. Doing so would attempt to add any previous skipped tokens
|
||||
// to this token we're skipping. We don't want to do that. Instead, we want to add
|
||||
// all the skipped tokens when we finally eat the next good token.
|
||||
source.consumeToken(token)
|
||||
}
|
||||
|
||||
function consumeToken(token: ISyntaxToken): ISyntaxToken {
|
||||
// Debug.assert(token.fullWidth() > 0 || token.kind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
// First, tell our source that the token has been consumed.
|
||||
source.consumeToken(token);
|
||||
|
||||
// Now, if we had any skipped tokens, we want to add them to the start of this token
|
||||
// we're consuming.
|
||||
if (_skippedTokens) {
|
||||
token = addSkippedTokensBeforeToken(token, _skippedTokens);
|
||||
_skippedTokens = undefined;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function addSkippedTokensBeforeToken(token: ISyntaxToken, skippedTokens: ISyntaxToken[]): ISyntaxToken {
|
||||
//Debug.assert(token.fullWidth() > 0 || token.kind === SyntaxKind.EndOfFileToken);
|
||||
//Debug.assert(skippedTokens.length > 0);
|
||||
|
||||
var leadingTrivia: ISyntaxTrivia[] = [];
|
||||
for (var i = 0, n = skippedTokens.length; i < n; i++) {
|
||||
var skippedToken = skippedTokens[i];
|
||||
addSkippedTokenToTriviaArray(leadingTrivia, skippedToken);
|
||||
}
|
||||
|
||||
addTriviaTo(token.leadingTrivia(source.text), leadingTrivia);
|
||||
|
||||
var updatedToken = Syntax.withLeadingTrivia(token, Syntax.triviaList(leadingTrivia), source.text);
|
||||
|
||||
// We've prepending this token with new leading trivia. This means the full start of
|
||||
// the token is not where the scanner originally thought it was, but is instead at the
|
||||
// start of the first skipped token.
|
||||
updatedToken.setFullStart(skippedTokens[0].fullStart());
|
||||
|
||||
return updatedToken;
|
||||
}
|
||||
|
||||
function addSkippedTokenToTriviaArray(array: ISyntaxTrivia[], skippedToken: ISyntaxToken): void {
|
||||
// Debug.assert(skippedToken.text().length > 0);
|
||||
|
||||
// first, add the leading trivia of the skipped token to the array
|
||||
addTriviaTo(skippedToken.leadingTrivia(source.text), array);
|
||||
|
||||
// now, add the text of the token as skipped text to the trivia array.
|
||||
var trimmedToken = Syntax.withTrailingTrivia(Syntax.withLeadingTrivia(skippedToken, Syntax.emptyTriviaList, source.text), Syntax.emptyTriviaList, source.text);
|
||||
|
||||
// Because we removed the leading trivia from the skipped token, the full start of the
|
||||
// trimmed token is the start of the skipped token.
|
||||
trimmedToken.setFullStart(start(skippedToken, source.text));
|
||||
|
||||
array.push(Syntax.skippedTokenTrivia(trimmedToken, source.text));
|
||||
|
||||
// Finally, add the trailing trivia of the skipped token to the trivia array.
|
||||
addTriviaTo(skippedToken.trailingTrivia(source.text), array);
|
||||
}
|
||||
|
||||
function addTriviaTo(list: ISyntaxTriviaList, array: ISyntaxTrivia[]): void {
|
||||
for (var i = 0, n = list.count(); i < n; i++) {
|
||||
array.push(list.syntaxTriviaAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
function consumeNode(node: ISyntaxNode): void {
|
||||
Debug.assert(_skippedTokens === undefined);
|
||||
source.consumeNode(node);
|
||||
}
|
||||
|
||||
@@ -366,13 +435,11 @@ module TypeScript.Parser {
|
||||
function eatIdentifierToken(diagnosticCode?: string): ISyntaxToken {
|
||||
var token = currentToken();
|
||||
if (isIdentifier(token)) {
|
||||
consumeToken(token);
|
||||
|
||||
if (token.kind === SyntaxKind.IdentifierName) {
|
||||
return token;
|
||||
return consumeToken(token);
|
||||
}
|
||||
|
||||
return TypeScript.Syntax.convertKeywordToIdentifier(token);
|
||||
return TypeScript.Syntax.convertKeywordToIdentifier(consumeToken(token));
|
||||
}
|
||||
|
||||
return createMissingToken(SyntaxKind.IdentifierName, token, diagnosticCode);
|
||||
@@ -523,182 +590,24 @@ module TypeScript.Parser {
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
function addSkippedTokenAfterNodeOrToken(nodeOrToken: ISyntaxNodeOrToken, skippedToken: ISyntaxToken): ISyntaxNodeOrToken {
|
||||
if (isToken(nodeOrToken)) {
|
||||
return addSkippedTokenAfterToken(<ISyntaxToken>nodeOrToken, skippedToken);
|
||||
}
|
||||
else if (isNode(nodeOrToken)) {
|
||||
return addSkippedTokenAfterNode(<ISyntaxNode>nodeOrToken, skippedToken);
|
||||
}
|
||||
else {
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
}
|
||||
|
||||
function replaceTokenInParent(node: ISyntaxNode, oldToken: ISyntaxToken, newToken: ISyntaxToken): void {
|
||||
// oldToken may be parented by a node or a list.
|
||||
replaceTokenInParentWorker(oldToken, newToken);
|
||||
|
||||
var parent = oldToken.parent;
|
||||
newToken.parent = parent;
|
||||
|
||||
// Walk upwards to our outermost node, clearing hte cached 'data' in it. This will
|
||||
// make sure that the fullWidths and incrementally unusable bits are computed correctly
|
||||
// when next requested.
|
||||
while (true) {
|
||||
// Parent must be a list or a node. All of those have a 'data' element.
|
||||
Debug.assert(isNode(parent) || isList(parent));
|
||||
var dataElement = <ISyntaxNode>parent;
|
||||
if (dataElement.__data) {
|
||||
dataElement.__data &= SyntaxConstants.NodeParsedInStrictModeMask
|
||||
}
|
||||
|
||||
dataElement.__cachedTokens = undefined;
|
||||
|
||||
if (parent === node) {
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
}
|
||||
|
||||
function replaceTokenInParentWorker(oldToken: ISyntaxToken, newToken: ISyntaxToken): void {
|
||||
var parent = oldToken.parent;
|
||||
|
||||
if (isNode(parent)) {
|
||||
var node = <any>parent;
|
||||
for (var key in node) {
|
||||
if (node[key] === oldToken) {
|
||||
node[key] = newToken;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isList(parent)) {
|
||||
var list1 = <ISyntaxNodeOrToken[]>parent;
|
||||
for (var i = 0, n = list1.length; i < n; i++) {
|
||||
if (list1[i] === oldToken) {
|
||||
list1[i] = newToken;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
function addSkippedTokenAfterNode(node: ISyntaxNode, skippedToken: ISyntaxToken): ISyntaxNode {
|
||||
var oldToken = lastToken(node);
|
||||
var newToken = addSkippedTokenAfterToken(oldToken, skippedToken);
|
||||
|
||||
replaceTokenInParent(node, oldToken, newToken);
|
||||
return node;
|
||||
}
|
||||
|
||||
function addSkippedTokensBeforeNode(node: ISyntaxNode, skippedTokens: ISyntaxToken[]): ISyntaxNode {
|
||||
if (skippedTokens.length > 0) {
|
||||
var oldToken = firstToken(node);
|
||||
var newToken = addSkippedTokensBeforeToken(oldToken, skippedTokens);
|
||||
|
||||
replaceTokenInParent(node, oldToken, newToken);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function addSkippedTokensBeforeToken(token: ISyntaxToken, skippedTokens: ISyntaxToken[]): ISyntaxToken {
|
||||
// Debug.assert(token.fullWidth() > 0 || token.kind === SyntaxKind.EndOfFileToken);
|
||||
// Debug.assert(skippedTokens.length > 0);
|
||||
|
||||
var leadingTrivia: ISyntaxTrivia[] = [];
|
||||
for (var i = 0, n = skippedTokens.length; i < n; i++) {
|
||||
var skippedToken = skippedTokens[i];
|
||||
addSkippedTokenToTriviaArray(leadingTrivia, skippedToken);
|
||||
}
|
||||
|
||||
addTriviaTo(token.leadingTrivia(source.text), leadingTrivia);
|
||||
|
||||
var updatedToken = Syntax.withLeadingTrivia(token, Syntax.triviaList(leadingTrivia), source.text);
|
||||
|
||||
// We've prepending this token with new leading trivia. This means the full start of
|
||||
// the token is not where the scanner originally thought it was, but is instead at the
|
||||
// start of the first skipped token.
|
||||
updatedToken.setFullStart(skippedTokens[0].fullStart());
|
||||
|
||||
// Don't need this array anymore. Give it back so we can reuse it.
|
||||
returnArray(skippedTokens);
|
||||
|
||||
return updatedToken;
|
||||
}
|
||||
|
||||
function addSkippedTokensAfterToken(token: ISyntaxToken, skippedTokens: ISyntaxToken[]): ISyntaxToken {
|
||||
// Debug.assert(token.fullWidth() > 0);
|
||||
if (skippedTokens.length === 0) {
|
||||
returnArray(skippedTokens);
|
||||
return token;
|
||||
}
|
||||
|
||||
var trailingTrivia = token.trailingTrivia(source.text).toArray();
|
||||
|
||||
for (var i = 0, n = skippedTokens.length; i < n; i++) {
|
||||
addSkippedTokenToTriviaArray(trailingTrivia, skippedTokens[i]);
|
||||
}
|
||||
|
||||
// Don't need this array anymore. Give it back so we can reuse it.
|
||||
returnArray(skippedTokens);
|
||||
return Syntax.withTrailingTrivia(token, Syntax.triviaList(trailingTrivia), source.text);
|
||||
}
|
||||
|
||||
function addSkippedTokenAfterToken(token: ISyntaxToken, skippedToken: ISyntaxToken): ISyntaxToken {
|
||||
// Debug.assert(token.fullWidth() > 0);
|
||||
var trailingTrivia = token.trailingTrivia(source.text).toArray();
|
||||
addSkippedTokenToTriviaArray(trailingTrivia, skippedToken);
|
||||
|
||||
return Syntax.withTrailingTrivia(token, Syntax.triviaList(trailingTrivia), source.text);
|
||||
}
|
||||
|
||||
function addSkippedTokenToTriviaArray(array: ISyntaxTrivia[], skippedToken: ISyntaxToken): void {
|
||||
// Debug.assert(skippedToken.text().length > 0);
|
||||
|
||||
// first, add the leading trivia of the skipped token to the array
|
||||
addTriviaTo(skippedToken.leadingTrivia(source.text), array);
|
||||
|
||||
// now, add the text of the token as skipped text to the trivia array.
|
||||
var trimmedToken = Syntax.withTrailingTrivia(Syntax.withLeadingTrivia(skippedToken, Syntax.emptyTriviaList, source.text), Syntax.emptyTriviaList, source.text);
|
||||
|
||||
// Because we removed the leading trivia from the skipped token, the full start of the
|
||||
// trimmed token is the start of the skipped token.
|
||||
trimmedToken.setFullStart(start(skippedToken, source.text));
|
||||
|
||||
array.push(Syntax.skippedTokenTrivia(trimmedToken, source.text));
|
||||
|
||||
// Finally, add the trailing trivia of the skipped token to the trivia array.
|
||||
addTriviaTo(skippedToken.trailingTrivia(source.text), array);
|
||||
}
|
||||
|
||||
function addTriviaTo(list: ISyntaxTriviaList, array: ISyntaxTrivia[]): void {
|
||||
for (var i = 0, n = list.count(); i < n; i++) {
|
||||
array.push(list.syntaxTriviaAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
function setStrictMode(_isInStrictMode: boolean) {
|
||||
isInStrictMode = _isInStrictMode;
|
||||
parseNodeData = _isInStrictMode ? SyntaxConstants.NodeParsedInStrictModeMask : 0;
|
||||
}
|
||||
|
||||
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 skippedTokens: ISyntaxToken[] = getArray();
|
||||
var moduleElements = parseSyntaxList<IModuleElementSyntax>(ListParsingState.SourceUnit_ModuleElements, skippedTokens, updateStrictModeState);
|
||||
|
||||
// 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.
|
||||
var moduleElements = parseSyntaxList<IModuleElementSyntax>(ListParsingState.SourceUnit_ModuleElements, updateStrictModeState);
|
||||
|
||||
setStrictMode(savedIsInStrictMode);
|
||||
|
||||
var sourceUnit = new SourceUnitSyntax(parseNodeData, moduleElements, currentToken());
|
||||
|
||||
sourceUnit = <SourceUnitSyntax>addSkippedTokensBeforeNode(sourceUnit, skippedTokens);
|
||||
var sourceUnit = new SourceUnitSyntax(parseNodeData, moduleElements, consumeToken(currentToken()));
|
||||
|
||||
if (Debug.shouldAssert(AssertionLevel.Aggressive)) {
|
||||
Debug.assert(fullWidth(sourceUnit) === source.text.length());
|
||||
@@ -849,13 +758,10 @@ module TypeScript.Parser {
|
||||
if (!inExpression) {
|
||||
// if we're not in an expression, this must be a type argument list. Just parse
|
||||
// it out as such.
|
||||
var lessThanToken = consumeToken(_currentToken);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var typeArguments = parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TypeArgumentList_Types, skippedTokens);
|
||||
lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens);
|
||||
|
||||
return new TypeArgumentListSyntax(parseNodeData, lessThanToken, typeArguments, eatToken(SyntaxKind.GreaterThanToken));
|
||||
return new TypeArgumentListSyntax(parseNodeData,
|
||||
consumeToken(_currentToken),
|
||||
parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TypeArgumentList_Types),
|
||||
eatToken(SyntaxKind.GreaterThanToken));
|
||||
}
|
||||
|
||||
// If we're in an expression, then we only want to consume this as a type argument list
|
||||
@@ -865,11 +771,7 @@ module TypeScript.Parser {
|
||||
|
||||
// We've seen a '<'. Try to parse it out as a type argument list.
|
||||
var lessThanToken = consumeToken(_currentToken);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var typeArguments = parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TypeArgumentList_Types, skippedTokens);
|
||||
var lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens);
|
||||
|
||||
var typeArguments = parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TypeArgumentList_Types);
|
||||
var greaterThanToken = eatToken(SyntaxKind.GreaterThanToken);
|
||||
|
||||
// We're in a context where '<' could be the start of a type argument list, or part
|
||||
@@ -991,9 +893,7 @@ module TypeScript.Parser {
|
||||
var enumElements: ISeparatedSyntaxList<EnumElementSyntax>;
|
||||
|
||||
if (openBraceToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
enumElements = parseSeparatedSyntaxList<EnumElementSyntax>(ListParsingState.EnumDeclaration_EnumElements, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
enumElements = parseSeparatedSyntaxList<EnumElementSyntax>(ListParsingState.EnumDeclaration_EnumElements);
|
||||
}
|
||||
|
||||
return new EnumDeclarationSyntax(parseNodeData, modifiers, enumKeyword, identifier, openBraceToken, enumElements || <any>[], eatToken(SyntaxKind.CloseBraceToken));
|
||||
@@ -1073,7 +973,7 @@ module TypeScript.Parser {
|
||||
}
|
||||
|
||||
function parseModifiers(): ISyntaxToken[] {
|
||||
var tokens: ISyntaxToken[] = getArray();
|
||||
var tokens: ISyntaxToken[] = [];
|
||||
|
||||
while (true) {
|
||||
var token = currentToken();
|
||||
@@ -1115,9 +1015,7 @@ module TypeScript.Parser {
|
||||
var classElements: IClassElementSyntax[];
|
||||
|
||||
if (openBraceToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
classElements = parseSyntaxList<IClassElementSyntax>(ListParsingState.ClassDeclaration_ClassElements, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
classElements = parseSyntaxList<IClassElementSyntax>(ListParsingState.ClassDeclaration_ClassElements);
|
||||
};
|
||||
|
||||
return new ClassDeclarationSyntax(parseNodeData,
|
||||
@@ -1333,9 +1231,8 @@ module TypeScript.Parser {
|
||||
start(token0, source.text), width(token0), DiagnosticCode.Unexpected_token_0_expected, [SyntaxFacts.getText(SyntaxKind.OpenBraceToken)]);
|
||||
addDiagnostic(diagnostic);
|
||||
|
||||
consumeToken(token0);
|
||||
|
||||
addSkippedTokenAfterNode(callSignature, token0);
|
||||
// Skip over the => It will get attached to whatever comes next.
|
||||
skipToken(token0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1390,9 +1287,7 @@ module TypeScript.Parser {
|
||||
|
||||
var moduleElements: IModuleElementSyntax[];
|
||||
if (openBraceToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
moduleElements = parseSyntaxList<IModuleElementSyntax>(ListParsingState.ModuleDeclaration_ModuleElements, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
moduleElements = parseSyntaxList<IModuleElementSyntax>(ListParsingState.ModuleDeclaration_ModuleElements);
|
||||
}
|
||||
|
||||
return new ModuleDeclarationSyntax(parseNodeData,
|
||||
@@ -1410,25 +1305,17 @@ module TypeScript.Parser {
|
||||
|
||||
var typeMembers: ISeparatedSyntaxList<ITypeMemberSyntax>;
|
||||
if (openBraceToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
typeMembers = parseSeparatedSyntaxList<ITypeMemberSyntax>(ListParsingState.ObjectType_TypeMembers, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
typeMembers = parseSeparatedSyntaxList<ITypeMemberSyntax>(ListParsingState.ObjectType_TypeMembers);
|
||||
}
|
||||
|
||||
return new ObjectTypeSyntax(parseNodeData, openBraceToken, typeMembers || <any>[], eatToken(SyntaxKind.CloseBraceToken));
|
||||
}
|
||||
|
||||
function parseTupleType(currentToken: ISyntaxToken): TupleTypeSyntax {
|
||||
var openBracket = consumeToken(currentToken);
|
||||
|
||||
var types: ISeparatedSyntaxList<ITypeSyntax>;
|
||||
if (openBracket.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
types = parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TupleType_Types, skippedTokens);
|
||||
openBracket = addSkippedTokensAfterToken(openBracket, skippedTokens);
|
||||
}
|
||||
|
||||
return new TupleTypeSyntax(parseNodeData, openBracket, types || <any>[], eatToken(SyntaxKind.CloseBracketToken));
|
||||
return new TupleTypeSyntax(parseNodeData,
|
||||
consumeToken(currentToken),
|
||||
parseSeparatedSyntaxList<ITypeSyntax>(ListParsingState.TupleType_Types),
|
||||
eatToken(SyntaxKind.CloseBracketToken));
|
||||
}
|
||||
|
||||
function isTypeMember(inErrorRecovery: boolean): boolean {
|
||||
@@ -1508,14 +1395,10 @@ module TypeScript.Parser {
|
||||
}
|
||||
|
||||
function parseIndexSignature(): IndexSignatureSyntax {
|
||||
var openBracketToken = eatToken(SyntaxKind.OpenBracketToken);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var parameters = parseSeparatedSyntaxList<ParameterSyntax>(ListParsingState.IndexSignature_Parameters, skippedTokens);
|
||||
openBracketToken = addSkippedTokensAfterToken(openBracketToken, skippedTokens);
|
||||
|
||||
return new IndexSignatureSyntax(parseNodeData,
|
||||
openBracketToken, parameters, eatToken(SyntaxKind.CloseBracketToken), parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false));
|
||||
eatToken(SyntaxKind.OpenBracketToken),
|
||||
parseSeparatedSyntaxList<ParameterSyntax>(ListParsingState.IndexSignature_Parameters),
|
||||
eatToken(SyntaxKind.CloseBracketToken), parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false));
|
||||
}
|
||||
|
||||
function parseMethodSignature(propertyName: IPropertyNameSyntax, questionToken: ISyntaxToken): MethodSignatureSyntax {
|
||||
@@ -1605,13 +1488,9 @@ module TypeScript.Parser {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
consumeToken(extendsOrImplementsKeyword);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var typeNames = parseSeparatedSyntaxList<INameSyntax>(ListParsingState.HeritageClause_TypeNameList, skippedTokens);
|
||||
extendsOrImplementsKeyword = addSkippedTokensAfterToken(extendsOrImplementsKeyword, skippedTokens);
|
||||
|
||||
return new HeritageClauseSyntax(parseNodeData, extendsOrImplementsKeyword, typeNames);
|
||||
return new HeritageClauseSyntax(parseNodeData,
|
||||
consumeToken(extendsOrImplementsKeyword),
|
||||
parseSeparatedSyntaxList<INameSyntax>(ListParsingState.HeritageClause_TypeNameList));
|
||||
}
|
||||
|
||||
function isInterfaceEnumClassModuleImportOrExport(modifierCount: number, _currentToken?: ISyntaxToken): boolean {
|
||||
@@ -1886,7 +1765,7 @@ module TypeScript.Parser {
|
||||
function parseForOrForInStatement(forKeyword: ISyntaxToken): IStatementSyntax {
|
||||
// Debug.assert(isForOrForInStatement());
|
||||
|
||||
consumeToken(forKeyword);
|
||||
forKeyword = consumeToken(forKeyword);
|
||||
var openParenToken = eatToken(SyntaxKind.OpenParenToken);
|
||||
|
||||
var _currentToken = currentToken();
|
||||
@@ -2007,7 +1886,7 @@ module TypeScript.Parser {
|
||||
function parseSwitchStatement(switchKeyword: ISyntaxToken) {
|
||||
// Debug.assert(isSwitchStatement());
|
||||
|
||||
consumeToken(switchKeyword);
|
||||
switchKeyword = consumeToken(switchKeyword);
|
||||
var openParenToken = eatToken(SyntaxKind.OpenParenToken);
|
||||
var expression: IExpressionSyntax;
|
||||
|
||||
@@ -2025,9 +1904,7 @@ module TypeScript.Parser {
|
||||
|
||||
var switchClauses: ISwitchClauseSyntax[];
|
||||
if (openBraceToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
switchClauses = parseSyntaxList<ISwitchClauseSyntax>(ListParsingState.SwitchStatement_SwitchClauses, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
switchClauses = parseSyntaxList<ISwitchClauseSyntax>(ListParsingState.SwitchStatement_SwitchClauses);
|
||||
}
|
||||
|
||||
return new SwitchStatementSyntax(parseNodeData, switchKeyword, openParenToken, expression, closeParenToken, openBraceToken, switchClauses || [], eatToken(SyntaxKind.CloseBraceToken));
|
||||
@@ -2066,38 +1943,20 @@ module TypeScript.Parser {
|
||||
function parseCaseSwitchClause(caseKeyword: ISyntaxToken): CaseSwitchClauseSyntax {
|
||||
// Debug.assert(isCaseSwitchClause());
|
||||
|
||||
consumeToken(caseKeyword);
|
||||
var expression = parseExpression(/*allowIn:*/ true);
|
||||
var colonToken = eatToken(SyntaxKind.ColonToken);
|
||||
var statements: IStatementSyntax[];
|
||||
|
||||
// TODO: allow parsing of the list evne if there's no colon. However, we have to make
|
||||
// sure we add any skipped tokens to the right previous node or token.
|
||||
if (colonToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
statements = parseSyntaxList<IStatementSyntax>(ListParsingState.SwitchClause_Statements, skippedTokens);
|
||||
colonToken = addSkippedTokensAfterToken(colonToken, skippedTokens);
|
||||
}
|
||||
|
||||
return new CaseSwitchClauseSyntax(parseNodeData, caseKeyword, expression, colonToken, statements || []);
|
||||
return new CaseSwitchClauseSyntax(parseNodeData,
|
||||
consumeToken(caseKeyword),
|
||||
parseExpression(/*allowIn:*/ true),
|
||||
eatToken(SyntaxKind.ColonToken),
|
||||
parseSyntaxList<IStatementSyntax>(ListParsingState.SwitchClause_Statements));
|
||||
}
|
||||
|
||||
function parseDefaultSwitchClause(defaultKeyword: ISyntaxToken): DefaultSwitchClauseSyntax {
|
||||
// Debug.assert(isDefaultSwitchClause());
|
||||
|
||||
consumeToken(defaultKeyword);
|
||||
var colonToken = eatToken(SyntaxKind.ColonToken);
|
||||
var statements: IStatementSyntax[];
|
||||
|
||||
// TODO: Allow parsing without a colon here. However, ensure that we attach any skipped
|
||||
// tokens to the defaultKeyword.
|
||||
if (colonToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
statements = parseSyntaxList<IStatementSyntax>(ListParsingState.SwitchClause_Statements, skippedTokens);
|
||||
colonToken = addSkippedTokensAfterToken(colonToken, skippedTokens);
|
||||
}
|
||||
|
||||
return new DefaultSwitchClauseSyntax(parseNodeData, defaultKeyword, colonToken, statements || []);
|
||||
return new DefaultSwitchClauseSyntax(parseNodeData,
|
||||
consumeToken(defaultKeyword),
|
||||
eatToken(SyntaxKind.ColonToken),
|
||||
parseSyntaxList<IStatementSyntax>(ListParsingState.SwitchClause_Statements));
|
||||
}
|
||||
|
||||
function parseThrowStatementExpression(): IExpressionSyntax {
|
||||
@@ -2245,18 +2104,13 @@ module TypeScript.Parser {
|
||||
function parseVariableDeclaration(allowIn: boolean): VariableDeclarationSyntax {
|
||||
// Debug.assert(currentToken().kind === SyntaxKind.VarKeyword);
|
||||
|
||||
var varKeyword = eatToken(SyntaxKind.VarKeyword);
|
||||
// Debug.assert(varKeyword.fullWidth() > 0);
|
||||
|
||||
var listParsingState = allowIn
|
||||
? ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn
|
||||
: ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn;
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var variableDeclarators = parseSeparatedSyntaxList<VariableDeclaratorSyntax>(listParsingState, skippedTokens);
|
||||
varKeyword = addSkippedTokensAfterToken(varKeyword, skippedTokens);
|
||||
|
||||
return new VariableDeclarationSyntax(parseNodeData, varKeyword, variableDeclarators);
|
||||
return new VariableDeclarationSyntax(parseNodeData,
|
||||
eatToken(SyntaxKind.VarKeyword),
|
||||
parseSeparatedSyntaxList<VariableDeclaratorSyntax>(listParsingState));
|
||||
}
|
||||
|
||||
function isVariableDeclarator(): boolean {
|
||||
@@ -2633,7 +2487,7 @@ module TypeScript.Parser {
|
||||
|
||||
switch (currentTokenKind) {
|
||||
case SyntaxKind.OpenParenToken:
|
||||
expression = new InvocationExpressionSyntax(parseNodeData, expression, parseArgumentList(/*typeArgumentList:*/ undefined));
|
||||
expression = new InvocationExpressionSyntax(parseNodeData, expression, parseArgumentList(/*typeArgumentList:*/ undefined, _currentToken));
|
||||
continue;
|
||||
|
||||
case SyntaxKind.LessThanToken:
|
||||
@@ -2740,7 +2594,7 @@ module TypeScript.Parser {
|
||||
}
|
||||
|
||||
function parseSuperExpression(superToken: ISyntaxToken): ILeftHandSideExpressionSyntax {
|
||||
var expression: ILeftHandSideExpressionSyntax = consumeToken(superToken);
|
||||
var expression = consumeToken(superToken);
|
||||
|
||||
// If we have seen "super" it must be followed by '(' or '.'.
|
||||
// If it wasn't then just try to parse out a '.' and report an error.
|
||||
@@ -2797,6 +2651,8 @@ module TypeScript.Parser {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
Debug.assert(typeArgumentList && isOpenParenOrDot);
|
||||
|
||||
releaseRewindPoint(rewindPoint);
|
||||
// It's not uncommon for a user to type: "Foo<T>."
|
||||
//
|
||||
@@ -2814,37 +2670,34 @@ module TypeScript.Parser {
|
||||
Syntax.emptyToken(SyntaxKind.OpenParenToken), <any>[], Syntax.emptyToken(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
else {
|
||||
return parseArgumentList(typeArgumentList);
|
||||
Debug.assert(token0.kind === SyntaxKind.OpenParenToken);
|
||||
return parseArgumentList(typeArgumentList, token0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseArgumentList(): ArgumentListSyntax {
|
||||
var tokenKind = currentToken().kind;
|
||||
var _currentToken = currentToken();
|
||||
var tokenKind = _currentToken.kind;
|
||||
if (tokenKind === SyntaxKind.LessThanToken) {
|
||||
return tryParseGenericArgumentList();
|
||||
}
|
||||
|
||||
if (tokenKind === SyntaxKind.OpenParenToken) {
|
||||
return parseArgumentList(undefined);
|
||||
return parseArgumentList(/*typeArgumentList:*/ undefined, /*openParenToken:*/ _currentToken);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseArgumentList(typeArgumentList: TypeArgumentListSyntax): ArgumentListSyntax {
|
||||
var openParenToken = eatToken(SyntaxKind.OpenParenToken);
|
||||
function parseArgumentList(typeArgumentList: TypeArgumentListSyntax, openParenToken: ISyntaxToken): ArgumentListSyntax {
|
||||
Debug.assert(openParenToken.kind === SyntaxKind.OpenParenToken && openParenToken.fullWidth() > 0);
|
||||
|
||||
// Don't use the name 'arguments' it prevents V8 from optimizing this method.
|
||||
var _arguments: ISeparatedSyntaxList<IExpressionSyntax>;
|
||||
|
||||
if (openParenToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
_arguments = parseSeparatedSyntaxList<IExpressionSyntax>(ListParsingState.ArgumentList_AssignmentExpressions, skippedTokens);
|
||||
openParenToken = addSkippedTokensAfterToken(openParenToken, skippedTokens);
|
||||
}
|
||||
|
||||
return new ArgumentListSyntax(parseNodeData, typeArgumentList, openParenToken, _arguments || <any>[], eatToken(SyntaxKind.CloseParenToken));
|
||||
return new ArgumentListSyntax(parseNodeData,
|
||||
typeArgumentList,
|
||||
consumeToken(openParenToken),
|
||||
parseSeparatedSyntaxList<IExpressionSyntax>(ListParsingState.ArgumentList_AssignmentExpressions),
|
||||
eatToken(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
|
||||
function tryParseArgumentListExpression(): IExpressionSyntax {
|
||||
@@ -2994,13 +2847,13 @@ module TypeScript.Parser {
|
||||
}
|
||||
|
||||
function parseTemplateExpression(startToken: ISyntaxToken): IPrimaryExpressionSyntax {
|
||||
consumeToken(startToken);
|
||||
startToken = consumeToken(startToken);
|
||||
|
||||
if (startToken.kind === SyntaxKind.NoSubstitutionTemplateToken) {
|
||||
return startToken;
|
||||
}
|
||||
|
||||
var templateClauses: TemplateClauseSyntax[] = getArray();
|
||||
var templateClauses: TemplateClauseSyntax[] = [];
|
||||
|
||||
do {
|
||||
// Keep consuming template spans as long as the last one we keep getting template
|
||||
@@ -3019,7 +2872,7 @@ module TypeScript.Parser {
|
||||
if (token.kind === SyntaxKind.CloseBraceToken) {
|
||||
token = currentContextualToken();
|
||||
Debug.assert(token.kind === SyntaxKind.TemplateMiddleToken || token.kind === SyntaxKind.TemplateEndToken);
|
||||
consumeToken(token);
|
||||
token = consumeToken(token);
|
||||
}
|
||||
else {
|
||||
var diagnostic = getExpectedTokenDiagnostic(SyntaxKind.CloseBraceToken);
|
||||
@@ -3321,15 +3174,10 @@ module TypeScript.Parser {
|
||||
|
||||
function parseObjectLiteralExpression(openBraceToken: ISyntaxToken): ObjectLiteralExpressionSyntax {
|
||||
// Debug.assert(currentToken().kind === SyntaxKind.OpenBraceToken);
|
||||
|
||||
consumeToken(openBraceToken);
|
||||
// Debug.assert(openBraceToken.fullWidth() > 0);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var propertyAssignments = parseSeparatedSyntaxList<IPropertyAssignmentSyntax>(ListParsingState.ObjectLiteralExpression_PropertyAssignments, skippedTokens);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
|
||||
return new ObjectLiteralExpressionSyntax(parseNodeData, openBraceToken, propertyAssignments, eatToken(SyntaxKind.CloseBraceToken));
|
||||
return new ObjectLiteralExpressionSyntax(parseNodeData,
|
||||
consumeToken(openBraceToken),
|
||||
parseSeparatedSyntaxList<IPropertyAssignmentSyntax>(ListParsingState.ObjectLiteralExpression_PropertyAssignments),
|
||||
eatToken(SyntaxKind.CloseBraceToken));
|
||||
}
|
||||
|
||||
function tryParsePropertyAssignment(inErrorRecovery: boolean): IPropertyAssignmentSyntax {
|
||||
@@ -3461,14 +3309,10 @@ module TypeScript.Parser {
|
||||
|
||||
function parseArrayLiteralExpression(openBracketToken: ISyntaxToken): ArrayLiteralExpressionSyntax {
|
||||
// Debug.assert(currentToken().kind === SyntaxKind.OpenBracketToken);
|
||||
consumeToken(openBracketToken);
|
||||
// Debug.assert(openBracketToken.fullWidth() > 0);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var expressions = parseSeparatedSyntaxList<IExpressionSyntax>(ListParsingState.ArrayLiteralExpression_AssignmentExpressions, skippedTokens);
|
||||
openBracketToken = addSkippedTokensAfterToken(openBracketToken, skippedTokens);
|
||||
|
||||
return new ArrayLiteralExpressionSyntax(parseNodeData, openBracketToken, expressions, eatToken(SyntaxKind.CloseBracketToken));
|
||||
return new ArrayLiteralExpressionSyntax(parseNodeData,
|
||||
consumeToken(openBracketToken),
|
||||
parseSeparatedSyntaxList<IExpressionSyntax>(ListParsingState.ArrayLiteralExpression_AssignmentExpressions),
|
||||
eatToken(SyntaxKind.CloseBracketToken));
|
||||
}
|
||||
|
||||
function parseBlock(parseBlockEvenWithNoOpenBrace: boolean, checkForStrictMode: boolean): BlockSyntax {
|
||||
@@ -3479,9 +3323,7 @@ module TypeScript.Parser {
|
||||
var savedIsInStrictMode = isInStrictMode;
|
||||
|
||||
var processItems = checkForStrictMode ? updateStrictModeState : undefined;
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var statements = parseSyntaxList<IStatementSyntax>(ListParsingState.Block_Statements, skippedTokens, processItems);
|
||||
openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens);
|
||||
var statements = parseSyntaxList<IStatementSyntax>(ListParsingState.Block_Statements, processItems);
|
||||
|
||||
setStrictMode(savedIsInStrictMode);
|
||||
}
|
||||
@@ -3503,10 +3345,7 @@ module TypeScript.Parser {
|
||||
var rewindPoint = getRewindPoint();
|
||||
|
||||
var lessThanToken = consumeToken(_currentToken);
|
||||
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
var typeParameters = parseSeparatedSyntaxList<TypeParameterSyntax>(ListParsingState.TypeParameterList_TypeParameters, skippedTokens);
|
||||
lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens);
|
||||
var typeParameters = parseSeparatedSyntaxList<TypeParameterSyntax>(ListParsingState.TypeParameterList_TypeParameters);
|
||||
|
||||
var greaterThanToken = eatToken(SyntaxKind.GreaterThanToken);
|
||||
|
||||
@@ -3560,9 +3399,7 @@ module TypeScript.Parser {
|
||||
var parameters: ISeparatedSyntaxList<ParameterSyntax>;
|
||||
|
||||
if (openParenToken.fullWidth() > 0) {
|
||||
var skippedTokens: ISyntaxToken[] = getArray();
|
||||
parameters = parseSeparatedSyntaxList<ParameterSyntax>(ListParsingState.ParameterList_Parameters, skippedTokens);
|
||||
openParenToken = addSkippedTokensAfterToken(openParenToken, skippedTokens);
|
||||
parameters = parseSeparatedSyntaxList<ParameterSyntax>(ListParsingState.ParameterList_Parameters);
|
||||
}
|
||||
|
||||
return new ParameterListSyntax(parseNodeData, openParenToken, parameters || <any>[], eatToken(SyntaxKind.CloseParenToken));
|
||||
@@ -3651,10 +3488,7 @@ module TypeScript.Parser {
|
||||
if (type) {
|
||||
var barToken: ISyntaxToken;
|
||||
while ((barToken = currentToken()).kind === SyntaxKind.BarToken) {
|
||||
consumeToken(barToken);
|
||||
var right = parsePrimaryType();
|
||||
|
||||
type = new UnionTypeSyntax(parseNodeData, type, barToken, right);
|
||||
type = new UnionTypeSyntax(parseNodeData, type, consumeToken(barToken), parsePrimaryType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3875,23 +3709,22 @@ module TypeScript.Parser {
|
||||
return new ParameterSyntax(parseNodeData, dotDotDotToken, modifiers, identifier, questionToken, typeAnnotation, equalsValueClause);
|
||||
}
|
||||
|
||||
function parseSyntaxList<T extends ISyntaxNodeOrToken>(
|
||||
currentListType: ListParsingState, skippedTokens: ISyntaxToken[], processItems?: (items: any[]) => void): T[] {
|
||||
function parseSyntaxList<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, processItems?: (items: any[]) => void): T[] {
|
||||
var savedListParsingState = listParsingState;
|
||||
listParsingState |= (1 << currentListType);
|
||||
|
||||
var result = parseSyntaxListWorker<T>(currentListType, skippedTokens, processItems);
|
||||
var result = parseSyntaxListWorker<T>(currentListType, processItems);
|
||||
|
||||
listParsingState = savedListParsingState;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseSeparatedSyntaxList<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): ISeparatedSyntaxList<T> {
|
||||
function parseSeparatedSyntaxList<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState): ISeparatedSyntaxList<T> {
|
||||
var savedListParsingState = listParsingState;
|
||||
listParsingState |= (1 << currentListType);
|
||||
|
||||
var result = parseSeparatedSyntaxListWorker<T>(currentListType, skippedTokens);
|
||||
var result = parseSeparatedSyntaxListWorker<T>(currentListType);
|
||||
|
||||
listParsingState = savedListParsingState;
|
||||
|
||||
@@ -3900,7 +3733,9 @@ module TypeScript.Parser {
|
||||
|
||||
// Returns true if we should abort parsing.
|
||||
function abortParsingListOrMoveToNextToken<T extends ISyntaxNodeOrToken>(
|
||||
currentListType: ListParsingState, nodeAndSeparators: ISyntaxNodeOrToken[], skippedTokens: ISyntaxToken[]): boolean {
|
||||
currentListType: ListParsingState,
|
||||
nodeAndSeparators: ISyntaxNodeOrToken[]): boolean {
|
||||
|
||||
// Ok. We're at a token that is not a terminator for the list and wasn't the start of
|
||||
// an item in the list. Definitely report an error for this token.
|
||||
reportUnexpectedTokenDiagnostic(currentListType);
|
||||
@@ -3920,34 +3755,12 @@ module TypeScript.Parser {
|
||||
|
||||
// Otherwise, if none of the lists we're in can capture this token, then we need to
|
||||
// unilaterally skip it. Note: we've already reported an error above.
|
||||
addSkippedTokenToList(nodeAndSeparators, skippedTokens, consumeToken(currentToken()));
|
||||
|
||||
skipToken(currentToken());
|
||||
|
||||
// Continue parsing this list. Attach this token to whatever we've seen already.
|
||||
return false;
|
||||
}
|
||||
|
||||
function addSkippedTokenToList(
|
||||
nodesAndSeparators: ISyntaxNodeOrToken[], skippedTokens: ISyntaxToken[], skippedToken: ISyntaxToken): void {
|
||||
// Now, add this skipped token to the last item we successfully parsed in the list. Or
|
||||
// add it to the list of skipped tokens if we haven't parsed anything. Our caller will
|
||||
// have to deal with them.
|
||||
//
|
||||
var length = nodesAndSeparators.length;
|
||||
|
||||
for (var i = length - 1; i >= 0; i--) {
|
||||
var item = nodesAndSeparators[i];
|
||||
var _lastToken = lastToken(item);
|
||||
if (_lastToken && _lastToken.fullWidth() > 0) {
|
||||
nodesAndSeparators[i] = addSkippedTokenAfterNodeOrToken(item, skippedToken);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't have anything in the list we could add to. Add to the skipped items array
|
||||
// for our caller to handle.
|
||||
skippedTokens.push(skippedToken);
|
||||
}
|
||||
|
||||
function tryParseExpectedListItem(
|
||||
currentListType: ListParsingState, inErrorRecovery: boolean, items: ISyntaxNodeOrToken[], processItems: (items: ISyntaxNodeOrToken[]) => void): boolean {
|
||||
var item = tryParseExpectedListItemWorker(currentListType, inErrorRecovery);
|
||||
@@ -3971,7 +3784,7 @@ module TypeScript.Parser {
|
||||
currentToken().kind === SyntaxKind.EndOfFileToken;
|
||||
}
|
||||
|
||||
function parseSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[], processItems: (items: ISyntaxNodeOrToken[]) => void ): T[] {
|
||||
function parseSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, processItems: (items: ISyntaxNodeOrToken[]) => void ): T[] {
|
||||
var items: T[] = [];
|
||||
|
||||
while (true) {
|
||||
@@ -3990,7 +3803,7 @@ module TypeScript.Parser {
|
||||
|
||||
// List wasn't complete and we didn't get an item. Figure out if we should bail out
|
||||
// or skip a token and continue.
|
||||
var abort = abortParsingListOrMoveToNextToken(currentListType, items, skippedTokens);
|
||||
var abort = abortParsingListOrMoveToNextToken(currentListType, items);
|
||||
if (abort) {
|
||||
break;
|
||||
}
|
||||
@@ -4003,7 +3816,7 @@ module TypeScript.Parser {
|
||||
return Syntax.list<T>(items);
|
||||
}
|
||||
|
||||
function parseSeparatedSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): ISeparatedSyntaxList<T> {
|
||||
function parseSeparatedSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState): ISeparatedSyntaxList<T> {
|
||||
var nodesAndSeparators: ISyntaxNodeOrToken[] = [];
|
||||
|
||||
// Debug.assert(nodes.length === 0);
|
||||
@@ -4036,7 +3849,7 @@ module TypeScript.Parser {
|
||||
|
||||
// List wasn't complete and we didn't get an item. Figure out if we should bail out
|
||||
// or skip a token and continue.
|
||||
var abort = abortParsingListOrMoveToNextToken(currentListType, nodesAndSeparators, skippedTokens);
|
||||
var abort = abortParsingListOrMoveToNextToken(currentListType, nodesAndSeparators);
|
||||
if (abort) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1622,6 +1622,8 @@ module TypeScript.Scanner {
|
||||
}
|
||||
|
||||
function consumeToken(token: ISyntaxToken): void {
|
||||
// Debug.assert(token.fullWidth() > 0 || token.kind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
// Debug.assert(currentToken() === token);
|
||||
_absolutePosition += token.fullWidth();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user