From d730e5ca5594ac2d9c8c1ff71965093ba91e2f67 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 1 Dec 2014 16:17:04 -0800 Subject: [PATCH] Remove 'missing' syntax kind. --- src/compiler/checker.ts | 33 +++++----- src/compiler/parser.ts | 61 ++++++++++++------- src/compiler/types.ts | 7 ++- src/services/formatting.ts | 4 +- src/services/services.ts | 20 +++--- src/services/signatureHelp.ts | 2 +- src/services/smartIndenter.ts | 6 +- ...umConflictsWithGlobalIdentifier.errors.txt | 6 +- .../reference/enumMemberResolution.errors.txt | 6 +- ...parserPostfixPostfixExpression1.errors.txt | 7 +-- .../parserPostfixUnaryExpression1.errors.txt | 7 +-- 11 files changed, 91 insertions(+), 68 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 431740af125..dad791fe8ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -338,7 +338,6 @@ module ts { // the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with // the given name can be found. function resolveName(location: Node, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol { - var result: Symbol; var lastLocation: Node; var propertyWithInvalidInitializer: Node; @@ -516,26 +515,27 @@ module ts { // Resolves a qualified name and any involved import aliases function resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol { + if (getFullWidth(name) === 0) { + return undefined; + } + if (name.kind === SyntaxKind.Identifier) { - var symbol = resolveName(location, (name).text, meaning, Diagnostics.Cannot_find_name_0, name); + var symbol = resolveName(location,(name).text, meaning, Diagnostics.Cannot_find_name_0, name); if (!symbol) { return; } } else if (name.kind === SyntaxKind.QualifiedName) { - var namespace = resolveEntityName(location, (name).left, SymbolFlags.Namespace); - if (!namespace || namespace === unknownSymbol || (name).right.kind === SyntaxKind.Missing) return; - var symbol = getSymbol(namespace.exports, (name).right.text, meaning); + var namespace = resolveEntityName(location,(name).left, SymbolFlags.Namespace); + if (!namespace || namespace === unknownSymbol || getFullWidth((name).right) === 0) return; + var symbol = getSymbol(namespace.exports,(name).right.text, meaning); if (!symbol) { error(location, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString((name).right)); return; } } - else { - // Missing identifier - return; - } + Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); return symbol.flags & meaning ? symbol : resolveImport(symbol); } @@ -4256,7 +4256,7 @@ module ts { function getResolvedSymbol(node: Identifier): Symbol { var links = getNodeLinks(node); if (!links.resolvedSymbol) { - links.resolvedSymbol = resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node) || unknownSymbol; + links.resolvedSymbol = (getFullWidth(node) > 0 && resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node)) || unknownSymbol; } return links.resolvedSymbol; } @@ -5344,7 +5344,7 @@ module ts { var templateExpression = tagExpression.template; var lastSpan = lastOrUndefined(templateExpression.templateSpans); Debug.assert(lastSpan !== undefined); // we should always have at least one span. - callIsIncomplete = lastSpan.literal.kind === SyntaxKind.Missing || isUnterminatedTemplateEnd(lastSpan.literal); + callIsIncomplete = getFullWidth(lastSpan.literal) === 0 || isUnterminatedTemplateEnd(lastSpan.literal); } else { // If the template didn't end in a backtick, or its beginning occurred right prior to EOF, @@ -7051,7 +7051,7 @@ module ts { var isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0; function reportImplementationExpectedError(node: FunctionLikeDeclaration): void { - if (node.name && node.name.kind === SyntaxKind.Missing) { + if (node.name && getFullWidth(node.name) === 0) { return; } @@ -8889,6 +8889,11 @@ module ts { } if (isExpression(entityName)) { + if (getFullWidth(entityName) === 0) { + // Missing entity name. + return undefined; + } + if (entityName.kind === SyntaxKind.Identifier) { // Include Import in the meaning, this ensures that we do not follow aliases to where they point and instead // return the alias symbol. @@ -8909,10 +8914,6 @@ module ts { } return getNodeLinks(entityName).resolvedSymbol; } - else { - // Missing identifier - return; - } } else if (isTypeReferenceIdentifier(entityName)) { var meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d0954a7f0d8..e6f57c6e7f3 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5,6 +5,10 @@ module ts { var nodeConstructors = new Array Node>(SyntaxKind.Count); + export function getFullWidth(node: Node) { + return node.end - node.pos; + } + export function getNodeConstructor(kind: SyntaxKind): new () => Node { return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); } @@ -75,13 +79,14 @@ module ts { // Computed property names will just be emitted as "[]", where is the source // text of the expression in the computed property. export function declarationNameToString(name: DeclarationName) { - return name.kind === SyntaxKind.Missing ? "(Missing)" : getTextOfNode(name); + return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); } export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic { node = getErrorSpanForNode(node); var file = getSourceFileOfNode(node); - var start = node.kind === SyntaxKind.Missing ? node.pos : skipTrivia(file.text, node.pos); + + var start = getFullWidth(node) === 0 ? node.pos : skipTrivia(file.text, node.pos); var length = node.end - start; return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2); @@ -1200,14 +1205,14 @@ module ts { return inStrictModeContext() ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord; } - function parseExpected(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean { + function parseExpected(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): boolean { if (token === t) { nextToken(); return true; } if (diagnosticMessage) { - error(diagnosticMessage); + error(diagnosticMessage, arg0); } else { error(Diagnostics._0_expected, tokenToString(t)); @@ -1276,8 +1281,24 @@ module ts { return node; } - function createMissingNode(pos?: number): Node { - return createNode(SyntaxKind.Missing, pos); + function createMissingNode(kind: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node { + if (diagnosticMessage) { + if (reportAtCurrentPosition) { + errorAtPos(scanner.getStartPos(), 0, diagnosticMessage, arg0); + } + else { + var start = scanner.getTokenPos(); + errorAtPos(start, scanner.getTextPos() - start, diagnosticMessage, arg0); + } + } + + return createMissingNodeWithoutError(kind); + } + + function createMissingNodeWithoutError(kind: SyntaxKind) { + var result = createNode(kind, scanner.getStartPos()); + (result).text = ""; + return finishNode(result); } function internIdentifier(text: string): string { @@ -1297,14 +1318,7 @@ module ts { return finishNode(node); } - error(diagnosticMessage || Diagnostics.Identifier_expected); - return createMissingIdentifier(); - } - - function createMissingIdentifier() { - var node = createMissingNode(); - node.text = ""; - return node; + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition:*/ false, diagnosticMessage || Diagnostics.Identifier_expected); } function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier { @@ -1660,8 +1674,10 @@ module ts { }); if (matchesPattern) { - errorAtPos(scanner.getTokenPos(), 0, Diagnostics.Identifier_expected); - return createMissingNode(); + // Report that we need an identifier. However, report it right after the dot, + // and not on the next token. This is because the next token might actually + // be an identifier and the error woudl be quite confusing. + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken:*/ true, Diagnostics.Identifier_expected); } } @@ -1705,8 +1721,8 @@ module ts { literal = parseLiteralNode(); } else { - parseExpected(SyntaxKind.CloseBraceToken); - literal = createMissingIdentifier(); + literal = createMissingNode( + SyntaxKind.TemplateTail, /*reportAtCurrentPosition:*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); } span.literal = literal; @@ -1821,7 +1837,7 @@ module ts { ? doInYieldContext(parseIdentifier) : parseIdentifier(); - if (node.name.kind === SyntaxKind.Missing && node.flags === 0 && isModifier(token)) { + if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { // in cases like // 'use strict' // function foo(static) @@ -3009,7 +3025,9 @@ module ts { // don't want to rollback just because we were missing a type arg. The grammar checker // will report the actual error later on. if (token === SyntaxKind.CommaToken) { - return createNode(SyntaxKind.Missing); + var result = createNode(SyntaxKind.TypeReference); + result.typeName = createMissingNodeWithoutError(SyntaxKind.Identifier); + return finishNode(result); } return parseType(); @@ -4202,7 +4220,6 @@ module ts { case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.Identifier: - case SyntaxKind.Missing: case SyntaxKind.RegularExpressionLiteral: case SyntaxKind.NumericLiteral: case SyntaxKind.StringLiteral: @@ -4533,7 +4550,7 @@ module ts { if (typeArguments) { for (var i = 0, n = typeArguments.length; i < n; i++) { var arg = typeArguments[i]; - if (arg.kind === SyntaxKind.Missing) { + if (arg.kind === SyntaxKind.TypeReference && getFullWidth((arg).typeName) === 0) { return grammarErrorAtPos(arg.pos, 0, Diagnostics.Type_expected); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bc7ca28e515..f4fc13f76d9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -137,8 +137,9 @@ module ts { SetKeyword, StringKeyword, TypeKeyword, + // Parse tree nodes - Missing, + // Names QualifiedName, ComputedPropertyName, @@ -235,6 +236,7 @@ module ts { // Top-level nodes SourceFile, Program, + // Synthesized list SyntaxList, // Enum value count @@ -263,7 +265,8 @@ module ts { FirstOperator = SemicolonToken, LastOperator = CaretEqualsToken, FirstBinaryOperator = LessThanToken, - LastBinaryOperator = CaretEqualsToken + LastBinaryOperator = CaretEqualsToken, + FirstNode = QualifiedName, } export const enum NodeFlags { diff --git a/src/services/formatting.ts b/src/services/formatting.ts index fc64329c3e0..d986048cac3 100644 --- a/src/services/formatting.ts +++ b/src/services/formatting.ts @@ -483,8 +483,8 @@ module ts.formatting { if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) { return inheritedIndentation; } - - if (child.kind === SyntaxKind.Missing) { + + if (child.getFullWidth() === 0) { return inheritedIndentation; } diff --git a/src/services/services.ts b/src/services/services.ts index e3012f42846..df762437e1e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -218,7 +218,7 @@ module ts { } private createChildren(sourceFile?: SourceFile) { - if (this.kind > SyntaxKind.Missing) { + if (this.kind >= SyntaxKind.FirstNode) { scanner.setText((sourceFile || this.getSourceFile()).text); var children: Node[] = []; var pos = this.pos; @@ -264,8 +264,11 @@ module ts { var children = this.getChildren(); for (var i = 0; i < children.length; i++) { var child = children[i]; - if (child.kind < SyntaxKind.Missing) return child; - if (child.kind > SyntaxKind.Missing) return child.getFirstToken(sourceFile); + if (child.kind < SyntaxKind.FirstNode) { + return child; + } + + return child.getFirstToken(sourceFile); } } @@ -273,8 +276,11 @@ module ts { var children = this.getChildren(sourceFile); for (var i = children.length - 1; i >= 0; i--) { var child = children[i]; - if (child.kind < SyntaxKind.Missing) return child; - if (child.kind > SyntaxKind.Missing) return child.getLastToken(sourceFile); + if (child.kind < SyntaxKind.FirstNode) { + return child; + } + + return child.getLastToken(sourceFile); } } } @@ -758,7 +764,7 @@ module ts { case SyntaxKind.Method: var functionDeclaration = node; - if (functionDeclaration.name && functionDeclaration.name.kind !== SyntaxKind.Missing) { + if (functionDeclaration.name && functionDeclaration.name.getFullWidth() > 0) { var lastDeclaration = namedDeclarations.length > 0 ? namedDeclarations[namedDeclarations.length - 1] : undefined; @@ -2888,7 +2894,7 @@ module ts { if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { var right = (location.parent).name; // Either the location is on the right of a property access, or on the left and the right is missing - if (right === location || (right && right.kind === SyntaxKind.Missing)){ + if (right === location || (right && right.getFullWidth() === 0)){ location = location.parent; } } diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index e2b65e3c6e1..b8cb181a287 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -386,7 +386,7 @@ module ts.SignatureHelp { // leading up to the next token in case the user is about to type in a TemplateMiddle or TemplateTail. if (template.kind === SyntaxKind.TemplateExpression) { var lastSpan = lastOrUndefined((template).templateSpans); - if (lastSpan.literal.kind === SyntaxKind.Missing) { + if (lastSpan.literal.getFullWidth() === 0) { applicableSpanEnd = skipTrivia(sourceFile.text, applicableSpanEnd, /*stopAfterLineBreak*/ false); } } diff --git a/src/services/smartIndenter.ts b/src/services/smartIndenter.ts index 3fbfe142282..d13d2a62c68 100644 --- a/src/services/smartIndenter.ts +++ b/src/services/smartIndenter.ts @@ -393,6 +393,10 @@ module ts.formatting { * This function is always called when position of the cursor is located after the node */ function isCompletedNode(n: Node, sourceFile: SourceFile): boolean { + if (n.getFullWidth() === 0) { + return false; + } + switch (n.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: @@ -426,8 +430,6 @@ module ts.formatting { return isCompletedNode((n).expression, sourceFile); case SyntaxKind.ArrayLiteralExpression: return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile); - case SyntaxKind.Missing: - return false; case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: // there is no such thing as terminator token for CaseClause\DefaultClause so for simplicitly always consider them non-completed diff --git a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt index b91ddad3eb4..e6859558f74 100644 --- a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt +++ b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(5,1): error TS1003: Identifier expected. +tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,29): error TS1003: Identifier expected. tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,9): error TS2304: Cannot find name 'IgnoreRulesSpecific'. @@ -7,9 +7,9 @@ tests/cases/compiler/enumConflictsWithGlobalIdentifier.ts(4,9): error TS2304: Ca IgnoreRulesSpecific = 0, } var x = IgnoreRulesSpecific. + +!!! error TS1003: Identifier expected. ~~~~~~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'IgnoreRulesSpecific'. var y = Position.IgnoreRulesSpecific; - -!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/enumMemberResolution.errors.txt b/tests/baselines/reference/enumMemberResolution.errors.txt index 18910485236..f446c0d7909 100644 --- a/tests/baselines/reference/enumMemberResolution.errors.txt +++ b/tests/baselines/reference/enumMemberResolution.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/enumMemberResolution.ts(5,1): error TS1003: Identifier expected. +tests/cases/compiler/enumMemberResolution.ts(4,29): error TS1003: Identifier expected. tests/cases/compiler/enumMemberResolution.ts(4,9): error TS2304: Cannot find name 'IgnoreRulesSpecific'. @@ -7,10 +7,10 @@ tests/cases/compiler/enumMemberResolution.ts(4,9): error TS2304: Cannot find nam IgnoreRulesSpecific = 0 } var x = IgnoreRulesSpecific. // error + +!!! error TS1003: Identifier expected. ~~~~~~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'IgnoreRulesSpecific'. var y = 1; - -!!! error TS1003: Identifier expected. var z = Position2.IgnoreRulesSpecific; // no error \ No newline at end of file diff --git a/tests/baselines/reference/parserPostfixPostfixExpression1.errors.txt b/tests/baselines/reference/parserPostfixPostfixExpression1.errors.txt index ad664b91ab5..07c7352bbfc 100644 --- a/tests/baselines/reference/parserPostfixPostfixExpression1.errors.txt +++ b/tests/baselines/reference/parserPostfixPostfixExpression1.errors.txt @@ -1,16 +1,13 @@ tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts(1,5): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts(1,7): error TS1109: Expression expected. tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts(1,1): error TS2304: Cannot find name 'a'. -tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts(1,7): error TS2357: The operand of an increment or decrement operator must be a variable, property or indexer. -==== tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixPostfixExpression1.ts (3 errors) ==== a++ ++; ~~ !!! error TS1005: ';' expected. ~ !!! error TS1109: Expression expected. ~ -!!! error TS2304: Cannot find name 'a'. - -!!! error TS2357: The operand of an increment or decrement operator must be a variable, property or indexer. \ No newline at end of file +!!! error TS2304: Cannot find name 'a'. \ No newline at end of file diff --git a/tests/baselines/reference/parserPostfixUnaryExpression1.errors.txt b/tests/baselines/reference/parserPostfixUnaryExpression1.errors.txt index 1e1f4ea709a..364efe36a73 100644 --- a/tests/baselines/reference/parserPostfixUnaryExpression1.errors.txt +++ b/tests/baselines/reference/parserPostfixUnaryExpression1.errors.txt @@ -1,16 +1,13 @@ tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts(1,8): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts(1,10): error TS1109: Expression expected. tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts(1,1): error TS2304: Cannot find name 'foo'. -tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts(1,10): error TS2357: The operand of an increment or decrement operator must be a variable, property or indexer. -==== tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Expressions/parserPostfixUnaryExpression1.ts (3 errors) ==== foo ++ ++; ~~ !!! error TS1005: ';' expected. ~ !!! error TS1109: Expression expected. ~~~ -!!! error TS2304: Cannot find name 'foo'. - -!!! error TS2357: The operand of an increment or decrement operator must be a variable, property or indexer. \ No newline at end of file +!!! error TS2304: Cannot find name 'foo'. \ No newline at end of file