@@ -67,11 +67,15 @@ object Scanners {
67
67
68
68
/** Generate an error at the given offset */
69
69
def error (msg : String , off : Offset = offset): Unit = {
70
- ctx.error (msg, source atSpan Span ( off) )
70
+ errorButContinue (msg, off)
71
71
token = ERROR
72
72
errOffset = off
73
73
}
74
74
75
+ def errorButContinue (msg : String , off : Offset = offset): Unit = {
76
+ ctx.error(msg, source atSpan Span (off))
77
+ }
78
+
75
79
/** signal an error where the input ended in the middle of a token */
76
80
def incompleteInputError (msg : String ): Unit = {
77
81
ctx.incompleteInputError(msg, source atSpan Span (offset))
@@ -129,19 +133,22 @@ object Scanners {
129
133
var i = 0
130
134
val len = strVal.length
131
135
while (i < len) {
132
- val d = digit2int(strVal charAt i, base)
133
- if (d < 0 ) {
134
- error(" malformed integer number" )
135
- return 0
136
- }
137
- if (value < 0 ||
138
- limit / (base / divider) < value ||
139
- limit - (d / divider) < value * (base / divider) &&
140
- ! (negated && limit == value * base - 1 + d)) {
141
- error(" integer number too large" )
142
- return 0
136
+ val c = strVal charAt i
137
+ if (! isNumberSeparator(c)) {
138
+ val d = digit2int(c, base)
139
+ if (d < 0 ) {
140
+ error(s " malformed integer number " )
141
+ return 0
142
+ }
143
+ if (value < 0 ||
144
+ limit / (base / divider) < value ||
145
+ limit - (d / divider) < value * (base / divider) &&
146
+ ! (negated && limit == value * base - 1 + d)) {
147
+ error(" integer number too large" )
148
+ return 0
149
+ }
150
+ value = value * base + d
143
151
}
144
- value = value * base + d
145
152
i += 1
146
153
}
147
154
if (negated) - value else value
@@ -153,10 +160,11 @@ object Scanners {
153
160
/** Convert current strVal, base to double value
154
161
*/
155
162
def floatVal (negated : Boolean ): Double = {
163
+ val text = removeNumberSeparators(strVal)
156
164
val limit : Double =
157
165
if (token == DOUBLELIT ) Double .MaxValue else Float .MaxValue
158
166
try {
159
- val value : Double = java.lang.Double .valueOf(strVal ).doubleValue()
167
+ val value : Double = java.lang.Double .valueOf(text ).doubleValue()
160
168
if (value > limit)
161
169
error(" floating point number too large" )
162
170
if (negated) - value else value
@@ -169,6 +177,17 @@ object Scanners {
169
177
170
178
def floatVal : Double = floatVal(false )
171
179
180
+ @ inline def isNumberSeparator (c : Char ): Boolean = c == '_'
181
+
182
+ @ inline def removeNumberSeparators (s : String ): String =
183
+ if (s.indexOf('_' ) > 0 ) s.replaceAllLiterally(" _" , " " ) /* .replaceAll("'","")*/ else s
184
+
185
+ // disallow trailing numeric separator char, but continue lexing
186
+ def checkNoTrailingSeparator (): Unit = {
187
+ if (isNumberSeparator(litBuf.last))
188
+ errorButContinue(" trailing separator is not allowed" , offset + litBuf.length - 1 )
189
+ }
190
+
172
191
}
173
192
174
193
class Scanner (source : SourceFile , override val startFrom : Offset = 0 )(implicit ctx : Context ) extends ScannerCommon (source)(ctx) {
@@ -911,27 +930,29 @@ object Scanners {
911
930
*/
912
931
protected def getFraction (): Unit = {
913
932
token = DOUBLELIT
914
- while ('0' <= ch && ch <= '9' ) {
933
+ while ('0' <= ch && ch <= '9' || isNumberSeparator(ch) ) {
915
934
putChar(ch)
916
935
nextChar()
917
936
}
937
+ checkNoTrailingSeparator()
918
938
if (ch == 'e' || ch == 'E' ) {
919
939
val lookahead = lookaheadReader()
920
940
lookahead.nextChar()
921
941
if (lookahead.ch == '+' || lookahead.ch == '-' ) {
922
942
lookahead.nextChar()
923
943
}
924
- if ('0' <= lookahead.ch && lookahead.ch <= '9' ) {
944
+ if ('0' <= lookahead.ch && lookahead.ch <= '9' || isNumberSeparator(ch) ) {
925
945
putChar(ch)
926
946
nextChar()
927
947
if (ch == '+' || ch == '-' ) {
928
948
putChar(ch)
929
949
nextChar()
930
950
}
931
- while ('0' <= ch && ch <= '9' ) {
951
+ while ('0' <= ch && ch <= '9' || isNumberSeparator(ch) ) {
932
952
putChar(ch)
933
953
nextChar()
934
954
}
955
+ checkNoTrailingSeparator()
935
956
}
936
957
token = DOUBLELIT
937
958
}
@@ -954,15 +975,18 @@ object Scanners {
954
975
/** Read a number into strVal and set base
955
976
*/
956
977
protected def getNumber (): Unit = {
957
- while (digit2int(ch, base) >= 0 ) {
978
+ while (isNumberSeparator(ch) || digit2int(ch, base) >= 0 ) {
958
979
putChar(ch)
959
980
nextChar()
960
981
}
982
+ checkNoTrailingSeparator()
961
983
token = INTLIT
962
984
if (base == 10 && ch == '.' ) {
963
985
val lch = lookaheadChar()
964
986
if ('0' <= lch && lch <= '9' ) {
965
- putChar('.' ); nextChar(); getFraction()
987
+ putChar('.' )
988
+ nextChar()
989
+ getFraction()
966
990
}
967
991
} else (ch : @ switch) match {
968
992
case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' =>
@@ -972,6 +996,9 @@ object Scanners {
972
996
token = LONGLIT
973
997
case _ =>
974
998
}
999
+
1000
+ checkNoTrailingSeparator()
1001
+
975
1002
setStrVal()
976
1003
}
977
1004
0 commit comments