Skip to content

Commit 778f101

Browse files
committed
Add basic parsing support for let and const
1 parent 873c1df commit 778f101

28 files changed

+557
-7
lines changed

src/compiler/diagnosticInformationMap.generated.ts

+4
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ module ts {
115115
Filename_0_differs_from_already_included_filename_1_only_in_casing: { code: 1149, category: DiagnosticCategory.Error, key: "Filename '{0}' differs from already included filename '{1}' only in casing" },
116116
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 1150, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
117117
An_enum_member_cannot_have_a_numeric_name: { code: 1151, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
118+
var_let_or_const_expected: { code: 1152, category: DiagnosticCategory.Error, key: "'var', 'let' or 'const' expected." },
119+
let_variable_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1153, category: DiagnosticCategory.Error, key: "'let' variable declarations are only available when targeting ECMAScript 6 and higher." },
120+
const_variable_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1154, category: DiagnosticCategory.Error, key: "'const' variable declarations are only available when targeting ECMAScript 6 and higher." },
121+
Const_must_be_intialized: { code: 1155, category: DiagnosticCategory.Error, key: "Const must be intialized." },
118122
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
119123
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
120124
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

+16
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,22 @@
451451
"category": "Error",
452452
"code": 1151
453453
},
454+
"'var', 'let' or 'const' expected.": {
455+
"category": "Error",
456+
"code": 1152
457+
},
458+
"'let' variable declarations are only available when targeting ECMAScript 6 and higher.": {
459+
"category": "Error",
460+
"code": 1153
461+
},
462+
"'const' variable declarations are only available when targeting ECMAScript 6 and higher.": {
463+
"category": "Error",
464+
"code": 1154
465+
},
466+
"Const must be intialized.": {
467+
"category": "Error",
468+
"code": 1155
469+
},
454470

455471
"Duplicate identifier '{0}'.": {
456472
"category": "Error",

src/compiler/emitter.ts

+41-5
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,12 @@ module ts {
11491149
write(" ");
11501150
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
11511151
if (node.declarations) {
1152-
emitToken(SyntaxKind.VarKeyword, endPos);
1152+
if (node.declarations[0] && node.declarations[0].flags & NodeFlags.Let) {
1153+
emitToken(SyntaxKind.LetKeyword, endPos);
1154+
}
1155+
else {
1156+
emitToken(SyntaxKind.VarKeyword, endPos);
1157+
}
11531158
write(" ");
11541159
emitCommaList(node.declarations, /*includeTrailingComma*/ false);
11551160
}
@@ -1169,7 +1174,12 @@ module ts {
11691174
write(" ");
11701175
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
11711176
if (node.declaration) {
1172-
emitToken(SyntaxKind.VarKeyword, endPos);
1177+
if (node.declaration.flags & NodeFlags.Let) {
1178+
emitToken(SyntaxKind.LetKeyword, endPos);
1179+
}
1180+
else {
1181+
emitToken(SyntaxKind.VarKeyword, endPos);
1182+
}
11731183
write(" ");
11741184
emit(node.declaration);
11751185
}
@@ -1298,7 +1308,17 @@ module ts {
12981308

12991309
function emitVariableStatement(node: VariableStatement) {
13001310
emitLeadingComments(node);
1301-
if (!(node.flags & NodeFlags.Export)) write("var ");
1311+
if (!(node.flags & NodeFlags.Export)) {
1312+
if (node.flags & NodeFlags.Let) {
1313+
write("let ");
1314+
}
1315+
else if (node.flags & NodeFlags.Const) {
1316+
write("const ");
1317+
}
1318+
else {
1319+
write("var ");
1320+
}
1321+
}
13021322
emitCommaList(node.declarations, /*includeTrailingComma*/ false);
13031323
write(";");
13041324
emitTrailingComments(node);
@@ -1774,7 +1794,15 @@ module ts {
17741794
if (node.flags & NodeFlags.Export) {
17751795
writeLine();
17761796
emitStart(node);
1777-
write("var ");
1797+
if (node.flags & NodeFlags.Let) {
1798+
write("let ");
1799+
}
1800+
else if (node.flags & NodeFlags.Const) {
1801+
write("const ");
1802+
}
1803+
else {
1804+
write("var ");
1805+
}
17781806
emit(node.name);
17791807
write(" = ");
17801808
emitModuleMemberName(node);
@@ -2822,7 +2850,15 @@ module ts {
28222850
if (hasDeclarationWithEmit) {
28232851
emitJsDocComments(node);
28242852
emitDeclarationFlags(node);
2825-
write("var ");
2853+
if (node.flags & NodeFlags.Let) {
2854+
write("let ");
2855+
}
2856+
else if (node.flags & NodeFlags.Const) {
2857+
write("const ");
2858+
}
2859+
else {
2860+
write("var ");
2861+
}
28262862
emitCommaList(node.declarations, emitVariableDeclaration);
28272863
write(";");
28282864
writeLine();

src/compiler/parser.ts

+39-2
Original file line numberDiff line numberDiff line change
@@ -2645,6 +2645,15 @@ module ts {
26452645
error(Diagnostics.Variable_declaration_list_cannot_be_empty);
26462646
}
26472647
}
2648+
else if (parseOptional(SyntaxKind.LetKeyword)) {
2649+
var declarations = parseVariableDeclarationList(NodeFlags.Let, true);
2650+
if (!declarations.length) {
2651+
error(Diagnostics.Variable_declaration_list_cannot_be_empty);
2652+
}
2653+
if (languageVersion < ScriptTarget.ES6) {
2654+
grammarErrorAtPos(declarations.pos, declarations.end - declarations.pos, Diagnostics.let_variable_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
2655+
}
2656+
}
26482657
else {
26492658
var varOrInit = parseExpression(true);
26502659
}
@@ -2970,6 +2979,8 @@ module ts {
29702979
return !inErrorRecovery;
29712980
case SyntaxKind.OpenBraceToken:
29722981
case SyntaxKind.VarKeyword:
2982+
case SyntaxKind.LetKeyword:
2983+
case SyntaxKind.ConstKeyword:
29732984
case SyntaxKind.FunctionKeyword:
29742985
case SyntaxKind.IfKeyword:
29752986
case SyntaxKind.DoKeyword:
@@ -3016,6 +3027,8 @@ module ts {
30163027
case SyntaxKind.OpenBraceToken:
30173028
return parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false);
30183029
case SyntaxKind.VarKeyword:
3030+
case SyntaxKind.LetKeyword:
3031+
case SyntaxKind.ConstKeyword:
30193032
return parseVariableStatement();
30203033
case SyntaxKind.FunctionKeyword:
30213034
return parseFunctionDeclaration();
@@ -3095,6 +3108,9 @@ module ts {
30953108
if (inAmbientContext && node.initializer && errorCountBeforeVariableDeclaration === file.syntacticErrors.length) {
30963109
grammarErrorAtPos(initializerStart, initializerFirstTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
30973110
}
3111+
if (!inAmbientContext && !node.initializer && flags & NodeFlags.Const) {
3112+
grammarErrorOnNode(node, Diagnostics.Const_must_be_intialized);
3113+
}
30983114
if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) {
30993115
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
31003116
// and its Identifier is eval or arguments
@@ -3112,13 +3128,30 @@ module ts {
31123128
var node = <VariableStatement>createNode(SyntaxKind.VariableStatement, pos);
31133129
if (flags) node.flags = flags;
31143130
var errorCountBeforeVarStatement = file.syntacticErrors.length;
3115-
parseExpected(SyntaxKind.VarKeyword);
3116-
node.declarations = parseVariableDeclarationList(flags, /*noIn*/false);
3131+
if (token === SyntaxKind.LetKeyword) {
3132+
node.flags |= NodeFlags.Let;
3133+
}
3134+
else if (token === SyntaxKind.ConstKeyword) {
3135+
node.flags |= NodeFlags.Const;
3136+
}
3137+
else if (token !== SyntaxKind.VarKeyword) {
3138+
error(Diagnostics.var_let_or_const_expected);
3139+
}
3140+
nextToken();
3141+
node.declarations = parseVariableDeclarationList(node.flags, /*noIn*/false);
31173142
parseSemicolon();
31183143
finishNode(node);
31193144
if (!node.declarations.length && file.syntacticErrors.length === errorCountBeforeVarStatement) {
31203145
grammarErrorOnNode(node, Diagnostics.Variable_declaration_list_cannot_be_empty);
31213146
}
3147+
if (languageVersion < ScriptTarget.ES6) {
3148+
if (node.flags & NodeFlags.Let) {
3149+
grammarErrorOnNode(node, Diagnostics.let_variable_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
3150+
}
3151+
else if (node.flags & NodeFlags.Const) {
3152+
grammarErrorOnNode(node, Diagnostics.const_variable_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
3153+
}
3154+
}
31223155
return node;
31233156
}
31243157

@@ -3697,6 +3730,8 @@ module ts {
36973730
function isDeclaration(): boolean {
36983731
switch (token) {
36993732
case SyntaxKind.VarKeyword:
3733+
case SyntaxKind.LetKeyword:
3734+
case SyntaxKind.ConstKeyword:
37003735
case SyntaxKind.FunctionKeyword:
37013736
return true;
37023737
case SyntaxKind.ClassKeyword:
@@ -3747,6 +3782,8 @@ module ts {
37473782
var result: Declaration;
37483783
switch (token) {
37493784
case SyntaxKind.VarKeyword:
3785+
case SyntaxKind.LetKeyword:
3786+
case SyntaxKind.ConstKeyword:
37503787
result = parseVariableStatement(pos, flags);
37513788
break;
37523789
case SyntaxKind.FunctionKeyword:

src/compiler/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ module ts {
245245
MultiLine = 0x00000100, // Multi-line array or object literal
246246
Synthetic = 0x00000200, // Synthetic node (for full fidelity)
247247
DeclarationFile = 0x00000400, // Node is a .d.ts file
248+
Let = 0x00000800,
249+
Const = 0x00001000,
248250

249251
Modifier = Export | Ambient | Public | Private | Protected | Static,
250252
AccessibilityModifier = Public | Private | Protected
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,27): error TS1039: Initializers are not allowed in ambient contexts.
2+
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,26): error TS1039: Initializers are not allowed in ambient contexts.
3+
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,18): error TS1039: Initializers are not allowed in ambient contexts.
4+
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,37): error TS1039: Initializers are not allowed in ambient contexts.
5+
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,51): error TS1039: Initializers are not allowed in ambient contexts.
6+
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,14): error TS1039: Initializers are not allowed in ambient contexts.
7+
tests/cases/compiler/constDeclarations-ambient-errors.ts(9,22): error TS1039: Initializers are not allowed in ambient contexts.
8+
9+
10+
==== tests/cases/compiler/constDeclarations-ambient-errors.ts (7 errors) ====
11+
12+
// error: no intialization expected in ambient declarations
13+
declare const c1: boolean = true;
14+
~
15+
!!! error TS1039: Initializers are not allowed in ambient contexts.
16+
declare const c2: number = 0;
17+
~
18+
!!! error TS1039: Initializers are not allowed in ambient contexts.
19+
declare const c3 = null, c4 :string = "", c5: any = 0;
20+
~
21+
!!! error TS1039: Initializers are not allowed in ambient contexts.
22+
~
23+
!!! error TS1039: Initializers are not allowed in ambient contexts.
24+
~
25+
!!! error TS1039: Initializers are not allowed in ambient contexts.
26+
27+
declare module M {
28+
const c6 = 0;
29+
~
30+
!!! error TS1039: Initializers are not allowed in ambient contexts.
31+
const c7: number = 7;
32+
~
33+
!!! error TS1039: Initializers are not allowed in ambient contexts.
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [constDeclarations-ambient.ts]
2+
3+
// No error
4+
declare const c1: boolean;
5+
declare const c2: number;
6+
declare const c3, c4 :string, c5: any;
7+
8+
declare module M {
9+
const c6;
10+
const c7: number;
11+
}
12+
13+
//// [constDeclarations-ambient.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/constDeclarations-ambient.ts ===
2+
3+
// No error
4+
declare const c1: boolean;
5+
>c1 : boolean
6+
7+
declare const c2: number;
8+
>c2 : number
9+
10+
declare const c3, c4 :string, c5: any;
11+
>c3 : any
12+
>c4 : string
13+
>c5 : any
14+
15+
declare module M {
16+
>M : typeof M
17+
18+
const c6;
19+
>c6 : any
20+
21+
const c7: number;
22+
>c7 : number
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
tests/cases/compiler/constDeclarations-errors.ts(3,7): error TS1155: const must be intialized.
2+
tests/cases/compiler/constDeclarations-errors.ts(4,7): error TS1155: const must be intialized.
3+
tests/cases/compiler/constDeclarations-errors.ts(5,7): error TS1155: const must be intialized.
4+
tests/cases/compiler/constDeclarations-errors.ts(5,11): error TS1155: const must be intialized.
5+
tests/cases/compiler/constDeclarations-errors.ts(5,15): error TS1155: const must be intialized.
6+
tests/cases/compiler/constDeclarations-errors.ts(5,27): error TS1155: const must be intialized.
7+
tests/cases/compiler/constDeclarations-errors.ts(8,5): error TS1109: Expression expected.
8+
tests/cases/compiler/constDeclarations-errors.ts(8,5): error TS1156: const must be declared inside a block.
9+
tests/cases/compiler/constDeclarations-errors.ts(8,11): error TS1155: const must be intialized.
10+
tests/cases/compiler/constDeclarations-errors.ts(8,13): error TS1005: ';' expected.
11+
tests/cases/compiler/constDeclarations-errors.ts(8,13): error TS1128: Declaration or statement expected.
12+
tests/cases/compiler/constDeclarations-errors.ts(8,18): error TS1128: Declaration or statement expected.
13+
tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1109: Expression expected.
14+
tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1156: const must be declared inside a block.
15+
tests/cases/compiler/constDeclarations-errors.ts(10,28): error TS1005: ';' expected.
16+
tests/cases/compiler/constDeclarations-errors.ts(10,11): error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'.
17+
18+
19+
==== tests/cases/compiler/constDeclarations-errors.ts (16 errors) ====
20+
21+
// error, missing intialicer
22+
const c1;
23+
~~
24+
!!! error TS1155: const must be intialized.
25+
const c2: number;
26+
~~
27+
!!! error TS1155: const must be intialized.
28+
const c3, c4, c5 :string, c6; // error, missing initialicer
29+
~~
30+
!!! error TS1155: const must be intialized.
31+
~~
32+
!!! error TS1155: const must be intialized.
33+
~~
34+
!!! error TS1155: const must be intialized.
35+
~~
36+
!!! error TS1155: const must be intialized.
37+
38+
// error, wrong context
39+
for(const c in {}) { }
40+
~~~~~
41+
!!! error TS1109: Expression expected.
42+
~~~~~~~
43+
!!! error TS1156: const must be declared inside a block.
44+
~
45+
!!! error TS1155: const must be intialized.
46+
~~
47+
!!! error TS1005: ';' expected.
48+
~~
49+
!!! error TS1128: Declaration or statement expected.
50+
~
51+
!!! error TS1128: Declaration or statement expected.
52+
53+
for(const c = 0; c < 9; c++) { }
54+
~~~~~
55+
!!! error TS1109: Expression expected.
56+
~~~~~~~~~~~~
57+
!!! error TS1156: const must be declared inside a block.
58+
~
59+
!!! error TS1005: ';' expected.
60+
~
61+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'.
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/constDeclarations-es5.ts(2,1): error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
2+
tests/cases/compiler/constDeclarations-es5.ts(3,1): error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
3+
tests/cases/compiler/constDeclarations-es5.ts(4,1): error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
4+
5+
6+
==== tests/cases/compiler/constDeclarations-es5.ts (3 errors) ====
7+
8+
const z7 = false;
9+
~~~~~~~~~~~~~~~~~
10+
!!! error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
11+
const z8: number = 23;
12+
~~~~~~~~~~~~~~~~~~~~~~
13+
!!! error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
14+
const z9 = 0, z10 :string = "", z11 = null;
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16+
!!! error TS1154: 'const' variable declarations are only available when targeting ECMAScript 6 and higher.
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [constDeclarations.ts]
2+
3+
// No error
4+
const c1 = false;
5+
const c2: number = 23;
6+
const c3 = 0, c4 :string = "", c5 = null;
7+
8+
9+
//// [constDeclarations.js]
10+
// No error
11+
const c1 = false;
12+
const c2 = 23;
13+
const c3 = 0, c4 = "", c5 = null;
14+
15+
16+
//// [constDeclarations.d.ts]
17+
declare const c1: boolean;
18+
declare const c2: number;
19+
declare const c3: number, c4: string, c5: any;

0 commit comments

Comments
 (0)