diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 254e2cb12ca..c890ba86ee0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -287,6 +287,7 @@ module ts { TypeArguments, // Type arguments in type argument list TupleElementTypes, // Element types in tuple element type list HeritageClauses, // Heritage clauses for a class or interface declaration. + ImportSpecifiers, // Named import clause's import specifier list Count // Number of parsing contexts } @@ -306,7 +307,7 @@ module ts { case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected; case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; - case ParsingContext.TypeReferences: return Diagnostics.Type_reference_expected; + case ParsingContext.TypeReferences: return Diagnostics.Type_reference_expected; case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected; case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected; case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected; @@ -318,6 +319,7 @@ module ts { case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected; case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected; + case ParsingContext.ImportSpecifiers: return Diagnostics.Identifier_expected; } }; @@ -1450,6 +1452,8 @@ module ts { return token === SyntaxKind.CommaToken || isStartOfType(); case ParsingContext.HeritageClauses: return isHeritageClause(); + case ParsingContext.ImportSpecifiers: + return isIdentifierOrKeyword(); } Debug.fail("Non-exhaustive case in 'isListElement'."); @@ -1486,6 +1490,7 @@ module ts { case ParsingContext.EnumMembers: case ParsingContext.ObjectLiteralMembers: case ParsingContext.ObjectBindingElements: + case ParsingContext.ImportSpecifiers: return token === SyntaxKind.CloseBraceToken; case ParsingContext.SwitchClauseStatements: return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword; @@ -4521,7 +4526,8 @@ module ts { function parseImportDeclarationOrStatement(fullStart: number, modifiers: ModifiersArray): ImportEqualsDeclaration | ImportStatement { parseExpected(SyntaxKind.ImportKeyword); if (token === SyntaxKind.StringLiteral || - token === SyntaxKind.AsteriskToken) { + token === SyntaxKind.AsteriskToken || + token === SyntaxKind.OpenBraceToken) { return parseImportStatement(fullStart, modifiers); } @@ -4598,7 +4604,7 @@ module ts { // ImportedDefaultBinding, NamedImports from var importClause = createNode(SyntaxKind.ImportClause); - importClause.bindings = parseNamespaceImport(); + importClause.bindings = token === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImports(); parseExpected(SyntaxKind.FromKeyword); return finishNode(importClause); } @@ -4613,6 +4619,36 @@ module ts { return finishNode(namespaceImport); } + function parseNamedImports(): NamedImports { + var namedImports = createNode(SyntaxKind.NamedImports); + + // NamedImports: + // { } + // { ImportsList } + // { ImportsList, } + + // ImportsList: + // ImportSpecifier + // ImportsList, ImportSpecifier + parseExpected(SyntaxKind.OpenBraceToken); + namedImports.elements = parseDelimitedList(ParsingContext.ImportSpecifiers, parseImportSpecifier); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(namedImports); + } + + function parseImportSpecifier(): ImportSpecifier { + var node = createNode(SyntaxKind.ImportSpecifier); + // ImportSpecifier: + // ImportedBinding + // IdentifierName as ImportedBinding + if (lookAhead(nextTokenIsAsKeyword)) { + node.propertyName = parseIdentifierName(); + parseExpected(SyntaxKind.AsKeyword); + } + node.name = parseIdentifier(); + return finishNode(node); + } + function parseExportAssignmentTail(fullStart: number, modifiers: ModifiersArray): ExportAssignment { var node = createNode(SyntaxKind.ExportAssignment, fullStart); setModifiers(node, modifiers); @@ -4642,8 +4678,8 @@ module ts { // Not true keywords so ensure an identifier follows return lookAhead(nextTokenIsIdentifierOrKeyword); case SyntaxKind.ImportKeyword: - // Not true keywords so ensure an identifier follows or is string literal or asterisk - return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteralOrAsterisk) ; + // Not true keywords so ensure an identifier follows or is string literal or asterisk or open brace + return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteralOrAsteriskOrOpenBrace) ; case SyntaxKind.ModuleKeyword: // Not a true keyword so ensure an identifier or string literal follows return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteral); @@ -4674,10 +4710,10 @@ module ts { return isIdentifierOrKeyword() || token === SyntaxKind.StringLiteral; } - function nextTokenIsIdentifierOrKeywordOrStringLiteralOrAsterisk() { + function nextTokenIsIdentifierOrKeywordOrStringLiteralOrAsteriskOrOpenBrace() { nextToken(); return isIdentifierOrKeyword() || token === SyntaxKind.StringLiteral || - token === SyntaxKind.AsteriskToken; + token === SyntaxKind.AsteriskToken || token === SyntaxKind.OpenBraceToken; } function nextTokenIsEqualsTokenOrDeclarationStart() { @@ -4690,6 +4726,10 @@ module ts { return isDeclarationStart(); } + function nextTokenIsAsKeyword() { + return nextToken() === SyntaxKind.AsKeyword; + } + function parseDeclaration(): ModuleElement { var fullStart = getNodePos(); var modifiers = parseModifiers(); diff --git a/tests/baselines/reference/es6ImportNamedImport.js b/tests/baselines/reference/es6ImportNamedImport.js new file mode 100644 index 00000000000..e8eee3fba19 --- /dev/null +++ b/tests/baselines/reference/es6ImportNamedImport.js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/es6ImportNamedImport.ts] //// + +//// [es6ImportNamedImport_0.ts] + +export var a = 10; +export var x = a; +export var m = a; + +//// [es6ImportNamedImport_1.ts] +import { } from "es6ImportNamedImport_0"; +import { a } from "es6ImportNamedImport_0"; +import { a as b } from "es6ImportNamedImport_0"; +import { x, a as y } from "es6ImportNamedImport_0"; +import { x as z, } from "es6ImportNamedImport_0"; +import { m, } from "es6ImportNamedImport_0"; + +//// [es6ImportNamedImport_0.js] +exports.a = 10; +exports.x = exports.a; +exports.m = exports.a; +//// [es6ImportNamedImport_1.js] diff --git a/tests/baselines/reference/es6ImportNamedImport.types b/tests/baselines/reference/es6ImportNamedImport.types new file mode 100644 index 00000000000..1e8c4f5af7c --- /dev/null +++ b/tests/baselines/reference/es6ImportNamedImport.types @@ -0,0 +1,21 @@ +=== tests/cases/compiler/es6ImportNamedImport_0.ts === + +export var a = 10; +>a : number + +export var x = a; +>x : number +>a : number + +export var m = a; +>m : number +>a : number + +=== tests/cases/compiler/es6ImportNamedImport_1.ts === +import { } from "es6ImportNamedImport_0"; +No type information for this code.import { a } from "es6ImportNamedImport_0"; +No type information for this code.import { a as b } from "es6ImportNamedImport_0"; +No type information for this code.import { x, a as y } from "es6ImportNamedImport_0"; +No type information for this code.import { x as z, } from "es6ImportNamedImport_0"; +No type information for this code.import { m, } from "es6ImportNamedImport_0"; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/es6ImportNamedImportInEs5.js b/tests/baselines/reference/es6ImportNamedImportInEs5.js new file mode 100644 index 00000000000..4a7a95c6dbd --- /dev/null +++ b/tests/baselines/reference/es6ImportNamedImportInEs5.js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/es6ImportNamedImportInEs5.ts] //// + +//// [es6ImportNamedImportInEs5_0.ts] + +export var a = 10; +export var x = a; +export var m = a; + +//// [es6ImportNamedImportInEs5_1.ts] +import { } from "es6ImportNamedImportInEs5_0"; +import { a } from "es6ImportNamedImportInEs5_0"; +import { a as b } from "es6ImportNamedImportInEs5_0"; +import { x, a as y } from "es6ImportNamedImportInEs5_0"; +import { x as z, } from "es6ImportNamedImportInEs5_0"; +import { m, } from "es6ImportNamedImportInEs5_0"; + +//// [es6ImportNamedImportInEs5_0.js] +exports.a = 10; +exports.x = exports.a; +exports.m = exports.a; +//// [es6ImportNamedImportInEs5_1.js] diff --git a/tests/baselines/reference/es6ImportNamedImportInEs5.types b/tests/baselines/reference/es6ImportNamedImportInEs5.types new file mode 100644 index 00000000000..5b8ed7a5e34 --- /dev/null +++ b/tests/baselines/reference/es6ImportNamedImportInEs5.types @@ -0,0 +1,21 @@ +=== tests/cases/compiler/es6ImportNamedImportInEs5_0.ts === + +export var a = 10; +>a : number + +export var x = a; +>x : number +>a : number + +export var m = a; +>m : number +>a : number + +=== tests/cases/compiler/es6ImportNamedImportInEs5_1.ts === +import { } from "es6ImportNamedImportInEs5_0"; +No type information for this code.import { a } from "es6ImportNamedImportInEs5_0"; +No type information for this code.import { a as b } from "es6ImportNamedImportInEs5_0"; +No type information for this code.import { x, a as y } from "es6ImportNamedImportInEs5_0"; +No type information for this code.import { x as z, } from "es6ImportNamedImportInEs5_0"; +No type information for this code.import { m, } from "es6ImportNamedImportInEs5_0"; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/es6ImportNamedImportParsingError.errors.txt b/tests/baselines/reference/es6ImportNamedImportParsingError.errors.txt new file mode 100644 index 00000000000..ae1fba6b038 --- /dev/null +++ b/tests/baselines/reference/es6ImportNamedImportParsingError.errors.txt @@ -0,0 +1,32 @@ +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(1,10): error TS1003: Identifier expected. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(1,12): error TS1109: Expression expected. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(1,14): error TS2304: Cannot find name 'from'. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(1,19): error TS1005: ';' expected. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(2,22): error TS1005: '=' expected. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(2,24): error TS2304: Cannot find name 'from'. +tests/cases/compiler/es6ImportNamedImportParsingError_1.ts(2,29): error TS1005: ';' expected. + + +==== tests/cases/compiler/es6ImportNamedImportParsingError_0.ts (0 errors) ==== + + export var a = 10; + export var x = a; + export var m = a; + +==== tests/cases/compiler/es6ImportNamedImportParsingError_1.ts (7 errors) ==== + import { * } from "es6ImportNamedImportParsingError_0"; + ~ +!!! error TS1003: Identifier expected. + ~ +!!! error TS1109: Expression expected. + ~~~~ +!!! error TS2304: Cannot find name 'from'. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1005: ';' expected. + import defaultBinding, from "es6ImportNamedImportParsingError_0"; + ~ +!!! error TS1005: '=' expected. + ~~~~ +!!! error TS2304: Cannot find name 'from'. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1005: ';' expected. \ No newline at end of file diff --git a/tests/cases/compiler/es6ImportNamedImport.ts b/tests/cases/compiler/es6ImportNamedImport.ts new file mode 100644 index 00000000000..1b5057d72fb --- /dev/null +++ b/tests/cases/compiler/es6ImportNamedImport.ts @@ -0,0 +1,15 @@ +// @target: es6 +// @module: commonjs + +// @filename: es6ImportNamedImport_0.ts +export var a = 10; +export var x = a; +export var m = a; + +// @filename: es6ImportNamedImport_1.ts +import { } from "es6ImportNamedImport_0"; +import { a } from "es6ImportNamedImport_0"; +import { a as b } from "es6ImportNamedImport_0"; +import { x, a as y } from "es6ImportNamedImport_0"; +import { x as z, } from "es6ImportNamedImport_0"; +import { m, } from "es6ImportNamedImport_0"; \ No newline at end of file diff --git a/tests/cases/compiler/es6ImportNamedImportInEs5.ts b/tests/cases/compiler/es6ImportNamedImportInEs5.ts new file mode 100644 index 00000000000..4acad0bf7cb --- /dev/null +++ b/tests/cases/compiler/es6ImportNamedImportInEs5.ts @@ -0,0 +1,15 @@ +// @target: es5 +// @module: commonjs + +// @filename: es6ImportNamedImportInEs5_0.ts +export var a = 10; +export var x = a; +export var m = a; + +// @filename: es6ImportNamedImportInEs5_1.ts +import { } from "es6ImportNamedImportInEs5_0"; +import { a } from "es6ImportNamedImportInEs5_0"; +import { a as b } from "es6ImportNamedImportInEs5_0"; +import { x, a as y } from "es6ImportNamedImportInEs5_0"; +import { x as z, } from "es6ImportNamedImportInEs5_0"; +import { m, } from "es6ImportNamedImportInEs5_0"; \ No newline at end of file diff --git a/tests/cases/compiler/es6ImportNamedImportParsingError.ts b/tests/cases/compiler/es6ImportNamedImportParsingError.ts new file mode 100644 index 00000000000..2bd9493418c --- /dev/null +++ b/tests/cases/compiler/es6ImportNamedImportParsingError.ts @@ -0,0 +1,11 @@ +// @target: es6 +// @module: commonjs + +// @filename: es6ImportNamedImportParsingError_0.ts +export var a = 10; +export var x = a; +export var m = a; + +// @filename: es6ImportNamedImportParsingError_1.ts +import { * } from "es6ImportNamedImportParsingError_0"; +import defaultBinding, from "es6ImportNamedImportParsingError_0"; \ No newline at end of file