Skip to content

Commit b9124a7

Browse files
committed
Merge pull request #385 from Microsoft/octal
Disallow octal literals in strict mode and ES5
2 parents 02d0b02 + cc7ca33 commit b9124a7

26 files changed

+103
-88
lines changed

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ module ts {
105105
An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1118, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." },
106106
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
107107
An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." },
108+
Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." },
108109
Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
109110
Extends_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 2018, category: DiagnosticCategory.Error, key: "Extends clause of exported class '{0}' has or is using private name '{1}'." },
110111
Implements_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 2019, category: DiagnosticCategory.Error, key: "Implements clause of exported class '{0}' has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@
412412
"category": "Error",
413413
"code": 1120
414414
},
415+
"Octal literals are not allowed in strict mode.": {
416+
"category": "Error",
417+
"code": 1121
418+
},
415419
"Duplicate identifier '{0}'.": {
416420
"category": "Error",
417421
"code": 2000

src/compiler/parser.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,29 @@ module ts {
10551055
function parseLiteralNode(): LiteralExpression {
10561056
var node = <LiteralExpression>createNode(token);
10571057
node.text = scanner.getTokenValue();
1058+
var tokenPos = scanner.getTokenPos();
10581059
nextToken();
1059-
return finishNode(node);
1060+
finishNode(node);
1061+
1062+
// Octal literals are not allowed in strict mode or ES5
1063+
// Note that theoretically the following condition would hold true literals like 009,
1064+
// which is not octal.But because of how the scanner separates the tokens, we would
1065+
// never get a token like this.Instead, we would get 00 and 9 as two separate tokens.
1066+
// We also do not need to check for negatives because any prefix operator would be part of a
1067+
// parent unary expression.
1068+
if (node.kind === SyntaxKind.NumericLiteral
1069+
&& sourceText.charCodeAt(tokenPos) === CharacterCodes._0
1070+
&& isOctalDigit(sourceText.charCodeAt(tokenPos + 1))) {
1071+
1072+
if (isInStrictMode) {
1073+
grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode);
1074+
}
1075+
else if (languageVersion >= ScriptTarget.ES5) {
1076+
grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);
1077+
}
1078+
}
1079+
1080+
return node;
10601081
}
10611082

10621083
function parseStringLiteral(): LiteralExpression {

src/compiler/scanner.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ module ts {
300300
return ch >= CharacterCodes._0 && ch <= CharacterCodes._9;
301301
}
302302

303+
export function isOctalDigit(ch: number): boolean {
304+
return ch >= CharacterCodes._0 && ch <= CharacterCodes._7;
305+
}
306+
303307
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number {
304308
while (true) {
305309
var ch = text.charCodeAt(pos);
@@ -360,7 +364,9 @@ module ts {
360364
var precedingLineBreak: boolean;
361365

362366
function error(message: DiagnosticMessage): void {
363-
if (onError) onError(message);
367+
if (onError) {
368+
onError(message);
369+
}
364370
}
365371

366372
function isIdentifierStart(ch: number): boolean {
@@ -398,6 +404,14 @@ module ts {
398404
return +(text.substring(start, end));
399405
}
400406

407+
function scanOctalDigits(): number {
408+
var start = pos;
409+
while (isOctalDigit(text.charCodeAt(pos))) {
410+
pos++;
411+
}
412+
return +(text.substring(start, pos));
413+
}
414+
401415
function scanHexDigits(count: number, exact?: boolean): number {
402416
var digits = 0;
403417
var value = 0;
@@ -681,7 +695,7 @@ module ts {
681695

682696
if (!commentClosed) {
683697
pos++;
684-
onError(Diagnostics.Asterisk_Slash_expected);
698+
error(Diagnostics.Asterisk_Slash_expected);
685699
}
686700

687701
if (onComment) {
@@ -708,6 +722,14 @@ module ts {
708722
tokenValue = "" + value;
709723
return SyntaxKind.NumericLiteral;
710724
}
725+
// Try to parse as an octal
726+
if (pos + 1 < len && isOctalDigit(text.charCodeAt(pos + 1))) {
727+
tokenValue = "" + scanOctalDigits();
728+
return SyntaxKind.NumericLiteral;
729+
}
730+
// This fall-through is a deviation from the EcmaScript grammar. The grammar says that a leading zero
731+
// can only be followed by an octal digit, a dot, or the end of the number literal. However, we are being
732+
// permissive and allowing decimal digits of the form 08* and 09* (which many browsers also do).
711733
case CharacterCodes._1:
712734
case CharacterCodes._2:
713735
case CharacterCodes._3:

tests/baselines/reference/literals.errors.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
==== tests/cases/conformance/expressions/literals/literals.ts (4 errors) ====
1+
==== tests/cases/conformance/expressions/literals/literals.ts (6 errors) ====
22

33
//typeof null is Null
44
//typeof true is Boolean
@@ -27,11 +27,15 @@
2727
var n = 1.0;
2828
var n = 1e4;
2929
var n = 001; // Error in ES5
30+
~~~
31+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
3032
var n = 0x1;
3133
var n = -1;
3234
var n = -1.0;
3335
var n = -1e-4;
3436
var n = -003; // Error in ES5
37+
~~~
38+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
3539
var n = -0x1;
3640

3741
var s: string;

tests/baselines/reference/literals.js

Lines changed: 0 additions & 68 deletions
This file was deleted.

tests/baselines/reference/objectLiteralErrors.errors.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (59 errors) ====
1+
==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (61 errors) ====
22

33
// Multiple properties with the same name
44
var e1 = { a: 0, a: 0 };
@@ -45,6 +45,8 @@
4545
!!! Duplicate identifier '0x0'.
4646
var e14 = { 0: 0, 000: 0 };
4747
~~~
48+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
49+
~~~
4850
!!! Duplicate identifier '000'.
4951
var e15 = { "100": 0, 1e2: 0 };
5052
~~~
@@ -129,6 +131,8 @@
129131
!!! Duplicate identifier '0x0'.
130132
var f14 = { 0: 0, get 000() { return 0; } };
131133
~~~
134+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
135+
~~~
132136
!!! An object literal cannot have property and accessor with the same name.
133137
~~~
134138
!!! Duplicate identifier '000'.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
==== tests/cases/conformance/parser/ecmascript5/StrictMode/octalLiteralInStrictModeES3.ts (1 errors) ====
2+
"use strict";
3+
03;
4+
~~
5+
!!! Octal literals are not allowed in strict mode.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
==== tests/cases/conformance/scanner/ecmascript3/scannerES3NumericLiteral3.ts (1 errors) ====
2+
01.0
3+
~~
4+
!!! ';' expected.

tests/baselines/reference/scannerES3NumericLiteral3.js

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral2.ts (1 errors) ====
2+
01
3+
~~
4+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.

tests/baselines/reference/scannerNumericLiteral2.js

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral3.ts (2 errors) ====
2+
01.0
3+
~~
4+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
5+
~~
6+
!!! ';' expected.

tests/baselines/reference/scannerNumericLiteral3.js

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral8.ts (1 errors) ====
2+
-03
3+
~~
4+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral9.ts (2 errors) ====
2+
009
3+
~~
4+
!!! Octal literals are not available when targeting ECMAScript 5 and higher.
5+
~
6+
!!! ';' expected.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"use strict";
2+
03;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
01
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
01.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
1e
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
1e0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
1e+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
// @target: ES5
12
1e+0
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @target: ES5
2+
-03
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @target: ES5
2+
009

0 commit comments

Comments
 (0)