diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c43d1074df..7a1bfafcb4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -467,9 +467,9 @@ module ts { if (!links.target) { links.target = resolvingSymbol; var node = getDeclarationOfKind(symbol, SyntaxKind.ImportDeclaration); - var target = node.externalModuleName ? - resolveExternalModuleName(node, node.externalModuleName) : - getSymbolOfPartOfRightHandSideOfImport(node.entityName, node); + var target = node.externalModuleName + ? resolveExternalModuleName(node, node.externalModuleName.expression) + : getSymbolOfPartOfRightHandSideOfImport(node.entityName, node); if (links.target === resolvingSymbol) { links.target = target || unknownSymbol; } @@ -546,7 +546,12 @@ module ts { return moduleName.substr(0, 2) === "./" || moduleName.substr(0, 3) === "../" || moduleName.substr(0, 2) === ".\\" || moduleName.substr(0, 3) === "..\\"; } - function resolveExternalModuleName(location: Node, moduleLiteral: LiteralExpression): Symbol { + function resolveExternalModuleName(location: Node, moduleExpression: Expression): Symbol { + if (moduleExpression.kind !== SyntaxKind.StringLiteral) { + return; + } + + var moduleLiteral = moduleExpression; var searchPath = getDirectoryPath(getSourceFile(location).filename); var moduleName = moduleLiteral.text; if (!moduleName) return; @@ -8368,12 +8373,17 @@ module ts { // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference // other external modules only through top - level external module names. // Relative external module names are not permitted. - if (isExternalModuleNameRelative(node.externalModuleName.text)) { - error(node, Diagnostics.Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); - target = unknownSymbol; + if (node.externalModuleName.expression.kind === SyntaxKind.StringLiteral) { + if (isExternalModuleNameRelative((node.externalModuleName.expression).text)) { + error(node, Diagnostics.Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); + target = unknownSymbol; + } + else { + target = resolveImport(symbol); + } } else { - target = resolveImport(symbol); + target = unknownSymbol; } } else { @@ -8948,8 +8958,8 @@ module ts { case SyntaxKind.StringLiteral: // External module name in an import declaration - if (node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).externalModuleName === node) { - var importSymbol = getSymbolOfNode(node.parent); + if (node.parent.parent.kind === SyntaxKind.ImportDeclaration && (node.parent.parent).externalModuleName.expression === node) { + var importSymbol = getSymbolOfNode(node.parent.parent); var moduleType = getTypeOfSymbol(importSymbol); return moduleType ? moduleType.symbol : undefined; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index df99de098f..f5e5c056de 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -671,7 +671,7 @@ module ts { } else { write("require("); - writeTextOfNode(currentSourceFile, node.externalModuleName); + writeTextOfNode(currentSourceFile, node.externalModuleName.expression); write(");"); } writer.writeLine(); @@ -3312,11 +3312,12 @@ module ts { emit(node.entityName); } else { + var literal = node.externalModuleName.expression; write("require("); - emitStart(node.externalModuleName); - emitLiteral(node.externalModuleName); - emitEnd(node.externalModuleName); - emitToken(SyntaxKind.CloseParenToken, node.externalModuleName.end); + emitStart(literal); + emitLiteral(literal); + emitEnd(literal); + emitToken(SyntaxKind.CloseParenToken, literal.end); } write(";"); emitEnd(node); @@ -3356,7 +3357,7 @@ module ts { write("[\"require\", \"exports\""); forEach(imports, imp => { write(", "); - emitLiteral(imp.externalModuleName); + emitLiteral(imp.externalModuleName.expression); }); forEach(node.amdDependencies, amdDependency => { var text = "\"" + amdDependency + "\""; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4534523795..9e8424030a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -394,6 +394,8 @@ module ts { return child((node).expression); case SyntaxKind.HeritageClause: return children((node).types); + case SyntaxKind.ExternalModuleReference: + return child((node).expression); } } @@ -1726,14 +1728,6 @@ module ts { return node; } - function parseStringLiteral(): LiteralExpression { - if (token === SyntaxKind.StringLiteral) { - return parseLiteralNode(/*internName:*/ true); - } - error(Diagnostics.String_literal_expected); - return createMissingNode(); - } - // TYPES function parseTypeReference(): TypeReferenceNode { @@ -1786,9 +1780,7 @@ module ts { function parseParameterType(): TypeNode { return parseOptional(SyntaxKind.ColonToken) - ? token === SyntaxKind.StringLiteral - ? parseStringLiteral() - : parseType() + ? token === SyntaxKind.StringLiteral ? parseLiteralNode(/*internName:*/ true) : parseType() : undefined; } @@ -3940,7 +3932,7 @@ module ts { function parseAmbientExternalModuleDeclaration(fullStart: number, flags: NodeFlags): ModuleDeclaration { var node = createNode(SyntaxKind.ModuleDeclaration, fullStart); node.flags = flags; - node.name = parseStringLiteral(); + node.name = parseLiteralNode(/*internName:*/ true); node.body = parseModuleBlock(); return finishNode(node); } @@ -3952,24 +3944,45 @@ module ts { : parseInternalModuleTail(fullStart, flags); } + function isExternalModuleReference() { + if (token === SyntaxKind.RequireKeyword) { + return lookAhead(() => { + nextToken(); + return token === SyntaxKind.OpenParenToken; + }); + } + + return false; + } + function parseImportDeclaration(fullStart: number, modifiers: ModifiersArray): ImportDeclaration { var node = createNode(SyntaxKind.ImportDeclaration, fullStart); setModifiers(node, modifiers); parseExpected(SyntaxKind.ImportKeyword); node.name = parseIdentifier(); parseExpected(SyntaxKind.EqualsToken); - var entityName = parseEntityName(/*allowReservedWords*/ false); - if (entityName.kind === SyntaxKind.Identifier && (entityName).text === "require" && parseOptional(SyntaxKind.OpenParenToken)) { - node.externalModuleName = parseStringLiteral(); - parseExpected(SyntaxKind.CloseParenToken); + if (isExternalModuleReference()) { + node.externalModuleName = parseExternalModuleReference(); } else { - node.entityName = entityName; + node.entityName = parseEntityName(/*allowReservedWords*/ false); } parseSemicolon(); return finishNode(node); } + function parseExternalModuleReference() { + var node = createNode(SyntaxKind.ExternalModuleReference); + parseExpected(SyntaxKind.RequireKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = parseExpression(); + if (node.expression.kind === SyntaxKind.StringLiteral) { + internIdentifier((node.expression).text); + } + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + function parseExportAssignmentTail(fullStart: number, modifiers: ModifiersArray): ExportAssignment { var node = createNode(SyntaxKind.ExportAssignment, fullStart); setModifiers(node, modifiers); @@ -4307,6 +4320,7 @@ module ts { case SyntaxKind.DeleteExpression: return checkDeleteExpression( node); case SyntaxKind.ElementAccessExpression: return checkElementAccessExpression(node); case SyntaxKind.ExportAssignment: return checkExportAssignment(node); + case SyntaxKind.ExternalModuleReference: return checkExternalModuleReference(node); case SyntaxKind.ForInStatement: return checkForInStatement(node); case SyntaxKind.ForStatement: return checkForStatement(node); case SyntaxKind.FunctionDeclaration: return checkFunctionDeclaration(node); @@ -4704,6 +4718,12 @@ module ts { } } + function checkExternalModuleReference(node: ExternalModuleReference) { + if (node.expression.kind !== SyntaxKind.StringLiteral) { + return grammarErrorOnNode(node.expression, Diagnostics.String_literal_expected); + } + } + function checkForInStatement(node: ForInStatement) { return checkVariableDeclarations(node.declarations) || checkForMoreThanOneDeclaration(node.declarations); @@ -4905,7 +4925,7 @@ module ts { return grammarErrorOnNode(statement, Diagnostics.An_export_assignment_cannot_be_used_in_an_internal_module); } else if (statement.kind === SyntaxKind.ImportDeclaration && (statement).externalModuleName) { - return grammarErrorOnNode((statement).externalModuleName, Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); + return grammarErrorOnNode((statement).externalModuleName.expression, Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); } } } @@ -5627,8 +5647,11 @@ module ts { function processImportedModules(file: SourceFile, basePath: string) { forEach(file.statements, node => { - if (node.kind === SyntaxKind.ImportDeclaration && (node).externalModuleName) { - var nameLiteral = (node).externalModuleName; + if (node.kind === SyntaxKind.ImportDeclaration && + (node).externalModuleName && + (node).externalModuleName.expression.kind === SyntaxKind.StringLiteral) { + + var nameLiteral = (node).externalModuleName.expression; var moduleName = nameLiteral.text; if (moduleName) { var searchPath = basePath; @@ -5653,8 +5676,11 @@ module ts { // The StringLiteral must specify a top - level external module name. // Relative external module names are not permitted forEachChild((node).body, node => { - if (node.kind === SyntaxKind.ImportDeclaration && (node).externalModuleName) { - var nameLiteral = (node).externalModuleName; + if (node.kind === SyntaxKind.ImportDeclaration && + (node).externalModuleName && + (node).externalModuleName.expression.kind === SyntaxKind.StringLiteral) { + + var nameLiteral = (node).externalModuleName.expression; var moduleName = nameLiteral.text; if (moduleName) { // TypeScript 1.0 spec (April 2014): 12.1.6 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e97aaeb2ed..0a636b94b0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -221,6 +221,8 @@ module ts { ModuleBlock, ImportDeclaration, ExportAssignment, + // Module references + ExternalModuleReference, // Clauses CaseClause, DefaultClause, @@ -730,7 +732,11 @@ module ts { export interface ImportDeclaration extends Declaration, ModuleElement { name: Identifier; entityName?: EntityName; - externalModuleName?: LiteralExpression; + externalModuleName?: ExternalModuleReference; + } + + export interface ExternalModuleReference extends Node { + expression?: Expression; } export interface ExportAssignment extends Statement, ModuleElement { diff --git a/src/services/services.ts b/src/services/services.ts index 0ef6ab02b7..a4569d8879 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1982,7 +1982,7 @@ module ts { function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { return node.kind === SyntaxKind.StringLiteral && (isNameOfModuleDeclaration(node) || - (node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).externalModuleName === node)); + (node.parent.parent.kind === SyntaxKind.ImportDeclaration && (node.parent.parent).externalModuleName.expression === node)); } /** Returns true if the position is within a comment */ @@ -3086,7 +3086,7 @@ module ts { displayParts.push(spacePart()); displayParts.push(keywordPart(SyntaxKind.RequireKeyword)); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); - displayParts.push(displayPart(getTextOfNode(importDeclaration.externalModuleName), SymbolDisplayPartKind.stringLiteral)); + displayParts.push(displayPart(getTextOfNode(importDeclaration.externalModuleName.expression), SymbolDisplayPartKind.stringLiteral)); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } else { diff --git a/tests/baselines/reference/importNonStringLiteral.errors.txt b/tests/baselines/reference/importNonStringLiteral.errors.txt index ce3dbb3e1e..7138680d70 100644 --- a/tests/baselines/reference/importNonStringLiteral.errors.txt +++ b/tests/baselines/reference/importNonStringLiteral.errors.txt @@ -1,12 +1,9 @@ tests/cases/conformance/externalModules/importNonStringLiteral.ts(2,22): error TS1141: String literal expected. -tests/cases/conformance/externalModules/importNonStringLiteral.ts(2,23): error TS1005: ';' expected. -==== tests/cases/conformance/externalModules/importNonStringLiteral.ts (2 errors) ==== +==== tests/cases/conformance/externalModules/importNonStringLiteral.ts (1 errors) ==== var x = "filename"; import foo = require(x); // invalid ~ !!! error TS1141: String literal expected. - ~ -!!! error TS1005: ';' expected. \ No newline at end of file