From eecf7ba638fa3c1e5f46b23a01e2418ed74aa953 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 26 Apr 2015 16:12:16 -0700 Subject: [PATCH] Support 'namespace' declarations for internal modules --- src/compiler/parser.ts | 22 ++++++++++++++++------ src/compiler/scanner.ts | 1 + src/compiler/types.ts | 6 ++++-- src/services/formatting/rules.ts | 2 +- src/services/services.ts | 7 +++++-- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1a06a2743ba..476c4ff06d1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3704,6 +3704,7 @@ module ts { return !isConstEnum; case SyntaxKind.InterfaceKeyword: case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: case SyntaxKind.EnumKeyword: case SyntaxKind.TypeKeyword: // When followed by an identifier, these do not start a statement but might @@ -4371,14 +4372,14 @@ module ts { return finishNode(node); } - function parseInternalModuleTail(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, flags: NodeFlags): ModuleDeclaration { + function parseModuleOrNamespaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, flags: NodeFlags): ModuleDeclaration { let node = createNode(SyntaxKind.ModuleDeclaration, fullStart); node.decorators = decorators; setModifiers(node, modifiers); node.flags |= flags; node.name = parseIdentifier(); node.body = parseOptional(SyntaxKind.DotToken) - ? parseInternalModuleTail(getNodePos(), /*decorators*/ undefined, /*modifiers:*/undefined, NodeFlags.Export) + ? parseModuleOrNamespaceDeclaration(getNodePos(), /*decorators*/ undefined, /*modifiers:*/undefined, NodeFlags.Export) : parseModuleBlock(); return finishNode(node); } @@ -4393,10 +4394,17 @@ module ts { } function parseModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ModuleDeclaration { - parseExpected(SyntaxKind.ModuleKeyword); - return token === SyntaxKind.StringLiteral - ? parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers) - : parseInternalModuleTail(fullStart, decorators, modifiers, modifiers ? modifiers.flags : 0); + let flags = modifiers ? modifiers.flags : 0; + if (parseOptional(SyntaxKind.NamespaceKeyword)) { + flags |= NodeFlags.Namespace; + } + else { + parseExpected(SyntaxKind.ModuleKeyword); + if (token === SyntaxKind.StringLiteral) { + return parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers); + } + } + return parseModuleOrNamespaceDeclaration(fullStart, decorators, modifiers, flags); } function isExternalModuleReference() { @@ -4631,6 +4639,7 @@ module ts { // Not true keywords so ensure an identifier follows or is string literal or asterisk or open brace return lookAhead(nextTokenCanFollowImportKeyword); case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: // Not a true keyword so ensure an identifier or string literal follows return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteral); case SyntaxKind.ExportKeyword: @@ -4715,6 +4724,7 @@ module ts { case SyntaxKind.EnumKeyword: return parseEnumDeclaration(fullStart, decorators, modifiers); case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: return parseModuleDeclaration(fullStart, decorators, modifiers); case SyntaxKind.ImportKeyword: return parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index df6c20a8107..f7224e619bb 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -76,6 +76,7 @@ module ts { "interface": SyntaxKind.InterfaceKeyword, "let": SyntaxKind.LetKeyword, "module": SyntaxKind.ModuleKeyword, + "namespace": SyntaxKind.NamespaceKeyword, "new": SyntaxKind.NewKeyword, "null": SyntaxKind.NullKeyword, "number": SyntaxKind.NumberKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6e7c15e9e39..2a2035bf40c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -138,6 +138,7 @@ module ts { DeclareKeyword, GetKeyword, ModuleKeyword, + NamespaceKeyword, RequireKeyword, NumberKeyword, SetKeyword, @@ -312,8 +313,9 @@ module ts { DeclarationFile = 0x00000800, // Node is a .d.ts file Let = 0x00001000, // Variable declaration Const = 0x00002000, // Variable declaration - OctalLiteral = 0x00004000, - ExportContext = 0x00008000, // Export context (initialized by binding) + OctalLiteral = 0x00004000, // Octal numeric literal + Namespace = 0x00008000, // Namespace declaration + ExportContext = 0x00010000, // Export context (initialized by binding) Modifier = Export | Ambient | Public | Private | Protected | Static | Default, AccessibilityModifier = Public | Private | Protected, diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 23c835eaec2..0b6a6ad0bdc 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -312,7 +312,7 @@ module ts.formatting { this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); // Add a space around certain TypeScript keywords - this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { diff --git a/src/services/services.ts b/src/services/services.ts index 98a7fe0499f..b6a2853031e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2991,7 +2991,8 @@ module ts { case SyntaxKind.OpenBracketToken: return containingNodeKind === SyntaxKind.ArrayLiteralExpression; // [ | - case SyntaxKind.ModuleKeyword: // module | + case SyntaxKind.ModuleKeyword: // module | + case SyntaxKind.NamespaceKeyword: // namespace | return true; case SyntaxKind.DotToken: @@ -3644,7 +3645,9 @@ module ts { } if (symbolFlags & SymbolFlags.Module) { addNewLineIfDisplayPartsExist(); - displayParts.push(keywordPart(SyntaxKind.ModuleKeyword)); + let declaration = getDeclarationOfKind(symbol, SyntaxKind.ModuleDeclaration); + let isNamespace = declaration && declaration.name && declaration.name.kind === SyntaxKind.Identifier; + displayParts.push(keywordPart(isNamespace ? SyntaxKind.NamespaceKeyword : SyntaxKind.ModuleKeyword)); displayParts.push(spacePart()); addFullSymbolName(symbol); }