11using System ;
22using System . Collections . Generic ;
33using System . Globalization ;
4+ using System . Numerics ;
45using System . Runtime . CompilerServices ;
56using System . Text ;
67using System . Text . RegularExpressions ;
@@ -887,20 +888,10 @@ static string SafeSubstring(string s, int startIndex, int length)
887888 // https://tc39.github.io/ecma262/#sec-literals-numeric-literals
888889
889890 public Token ScanHexLiteral ( int start )
890- {
891- var index = Index ;
892-
893- while ( ! Eof ( ) )
894- {
895- if ( ! Character . IsHexDigit ( Source . CharCodeAt ( Index ) ) )
896- {
897- break ;
898- }
899-
900- Index ++ ;
901- }
902-
903- var number = Source . Substring ( index , Index - index ) ;
891+ {
892+ var sb = GetStringBuilder ( ) ;
893+ this . ScanLiteralPart ( sb , Character . IsHexDigit ) ;
894+ var number = sb . ToString ( ) ;
904895
905896 if ( number . Length == 0 )
906897 {
@@ -957,22 +948,11 @@ public Token ScanHexLiteral(int start)
957948 }
958949
959950 public Token ScanBinaryLiteral ( int start )
960- {
951+ {
961952 char ch ;
962- var index = Index ;
963-
964- while ( ! Eof ( ) )
965- {
966- ch = Source [ Index ] ;
967- if ( ch != '0' && ch != '1' )
968- {
969- break ;
970- }
971-
972- Index ++ ;
973- }
974-
975- var number = Source . Substring ( index , Index - index ) ;
953+ var sb = GetStringBuilder ( ) ;
954+ this . ScanLiteralPart ( sb , c => c == '0' || c == '1' ) ;
955+ var number = sb . ToString ( ) ;
976956
977957 if ( number . Length == 0 )
978958 {
@@ -1015,18 +995,9 @@ public Token ScanOctalLiteral(char prefix, int start)
1015995 else
1016996 {
1017997 ++ Index ;
1018- }
1019-
1020- while ( ! Eof ( ) )
1021- {
1022- if ( ! Character . IsOctalDigit ( Source . CharCodeAt ( Index ) ) )
1023- {
1024- break ;
1025- }
1026-
1027- sb . Append ( Source [ Index ++ ] ) ;
1028- }
1029-
998+ }
999+
1000+ this . ScanLiteralPart ( sb , Character . IsOctalDigit ) ;
10301001 var number = sb . ToString ( ) ;
10311002
10321003 if ( ! octal && number . Length == 0 )
@@ -1084,6 +1055,40 @@ public bool IsImplicitOctalLiteral()
10841055 return true ;
10851056 }
10861057
1058+ private void ScanLiteralPart ( StringBuilder sb , Func < char , bool > check )
1059+ {
1060+ var charCode = Source . CharCodeAt ( Index ) ;
1061+ if ( charCode == '_' )
1062+ {
1063+ ThrowUnexpectedToken ( Messages . NumericSeperatorNotAllowedHere ) ;
1064+ }
1065+
1066+ while ( ( check ( charCode ) || charCode == '_' ) )
1067+ {
1068+ if ( charCode != '_' )
1069+ {
1070+ sb . Append ( charCode ) ;
1071+ }
1072+ Index ++ ;
1073+ var newCharCode = Source . CharCodeAt ( Index ) ;
1074+ if ( charCode == '_' && newCharCode == '_' )
1075+ {
1076+ ThrowUnexpectedToken ( Messages . NumericSeperatorOneUnderscore ) ;
1077+ }
1078+
1079+ if ( Eof ( ) )
1080+ {
1081+ break ;
1082+ }
1083+ charCode = newCharCode ;
1084+ }
1085+
1086+ if ( charCode == '_' )
1087+ {
1088+ ThrowUnexpectedToken ( Messages . NumericSeperatorNotAllowedHere ) ;
1089+ }
1090+ }
1091+
10871092 public Token ScanNumericLiteral ( )
10881093 {
10891094 var sb = GetStringBuilder ( ) ;
@@ -1095,7 +1100,6 @@ public Token ScanNumericLiteral()
10951100 if ( ch != '.' )
10961101 {
10971102 var first = Source [ Index ++ ] ;
1098- sb . Append ( first ) ;
10991103 ch = Source . CharCodeAt ( Index ) ;
11001104
11011105 // Hex number starts with '0x'.
@@ -1130,21 +1134,15 @@ public Token ScanNumericLiteral()
11301134 }
11311135 }
11321136
1133- while ( Character . IsDecimalDigit ( Source . CharCodeAt ( Index ) ) )
1134- {
1135- sb . Append ( Source [ Index ++ ] ) ;
1136- }
1137-
1137+ -- Index ;
1138+ this . ScanLiteralPart ( sb , Character . IsDecimalDigit ) ;
11381139 ch = Source . CharCodeAt ( Index ) ;
11391140 }
11401141
11411142 if ( ch == '.' )
11421143 {
1143- sb . Append ( Source [ Index ++ ] ) ;
1144- while ( Character . IsDecimalDigit ( Source . CharCodeAt ( Index ) ) )
1145- {
1146- sb . Append ( Source [ Index ++ ] ) ;
1147- }
1144+ sb . Append ( Source [ Index ++ ] ) ;
1145+ this . ScanLiteralPart ( sb , Character . IsDecimalDigit ) ;
11481146
11491147 ch = Source . CharCodeAt ( Index ) ;
11501148 }
@@ -1161,15 +1159,27 @@ public Token ScanNumericLiteral()
11611159
11621160 if ( Character . IsDecimalDigit ( Source . CharCodeAt ( Index ) ) )
11631161 {
1164- while ( Character . IsDecimalDigit ( Source . CharCodeAt ( Index ) ) )
1165- {
1166- sb . Append ( Source [ Index ++ ] ) ;
1167- }
1162+ this . ScanLiteralPart ( sb , Character . IsDecimalDigit ) ;
11681163 }
11691164 else
11701165 {
11711166 ThrowUnexpectedToken ( ) ;
11721167 }
1168+ }
1169+ else if ( ch == 'n' )
1170+ {
1171+ Index ++ ;
1172+ var bigInt = BigInteger . Parse ( sb . ToString ( ) ) ;
1173+ return new Token
1174+ {
1175+ Type = TokenType . BigIntLiteral ,
1176+ Value = bigInt ,
1177+ BigIntValue = bigInt ,
1178+ LineNumber = LineNumber ,
1179+ LineStart = LineStart ,
1180+ Start = start ,
1181+ End = Index
1182+ } ;
11731183 }
11741184
11751185 if ( Character . IsIdentifierStart ( Source . CharCodeAt ( Index ) ) )
0 commit comments