Skip to content

Commit 50ee303

Browse files
authored
Merge pull request #8269 from som-snytt/issue/numbers
Accept 0x_42, reject 0x
2 parents 8f0b68e + 149e862 commit 50ee303

File tree

7 files changed

+112
-162
lines changed

7 files changed

+112
-162
lines changed

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,11 @@ object Scanners {
129129

130130
@inline def isNumberSeparator(c: Char): Boolean = c == '_'
131131

132-
@inline def removeNumberSeparators(s: String): String =
133-
if (s.indexOf('_') > 0) s.replaceAllLiterally("_", "") else s
132+
@inline def removeNumberSeparators(s: String): String = if (s.indexOf('_') == -1) s else s.replace("_", "")
134133

135134
// disallow trailing numeric separator char, but continue lexing
136135
def checkNoTrailingSeparator(): Unit =
137-
if (isNumberSeparator(litBuf.last))
136+
if (!litBuf.isEmpty && isNumberSeparator(litBuf.last))
138137
errorButContinue("trailing separator is not allowed", offset + litBuf.length - 1)
139138
}
140139

@@ -713,28 +712,18 @@ object Scanners {
713712
getOperatorRest()
714713
}
715714
case '0' =>
716-
def fetchZero() = {
717-
putChar(ch)
715+
def fetchLeadingZero(): Unit = {
718716
nextChar()
719-
if (ch == 'x' || ch == 'X') {
720-
nextChar()
721-
base = 16
722-
if (isNumberSeparator(ch))
723-
errorButContinue("leading separator is not allowed", offset + 2)
717+
ch match {
718+
case 'x' | 'X' => base = 16 ; nextChar()
719+
//case 'b' | 'B' => base = 2 ; nextChar()
720+
case _ => base = 10 ; putChar('0')
724721
}
725-
else {
726-
/**
727-
* What should leading 0 be in the future? It is potentially dangerous
728-
* to let it be base-10 because of history. Should it be an error? Is
729-
* there a realistic situation where one would need it?
730-
*/
731-
if (isDigit(ch) || (isNumberSeparator(ch) && isDigit(lookaheadChar())))
732-
error("Numbers may not have a leading zero.")
733-
base = 10
734-
}
735-
getNumber()
722+
if (base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0)
723+
error("invalid literal number")
736724
}
737-
fetchZero()
725+
fetchLeadingZero()
726+
getNumber()
738727
case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
739728
base = 10
740729
getNumber()

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,11 +633,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
633633
lazy val actualErrors = reporters.foldLeft(0)(_ + _.errorCount)
634634
def hasMissingAnnotations = getMissingExpectedErrors(errorMap, reporters.iterator.flatMap(_.errors))
635635

636-
if (compilerCrashed) Some(s"Compiler crashed when compiling: ${testSource.title}" )
637-
else if (actualErrors == 0) Some(s"\nNo errors found when compiling neg test $testSource" )
636+
if (compilerCrashed) Some(s"Compiler crashed when compiling: ${testSource.title}")
637+
else if (actualErrors == 0) Some(s"\nNo errors found when compiling neg test $testSource")
638638
else if (expectedErrors != actualErrors) Some(s"\nWrong number of errors encountered when compiling $testSource, expected: $expectedErrors, actual: $actualErrors")
639-
else if (hasMissingAnnotations) Some(s"\nErrors found on incorrect row numbers when compiling $testSource" )
640-
else if (!errorMap.isEmpty) Some(s"\nExpected error(s) have {<error position>=<unreported error>}: $errorMap" )
639+
else if (hasMissingAnnotations) Some(s"\nErrors found on incorrect row numbers when compiling $testSource")
640+
else if (!errorMap.isEmpty) Some(s"\nExpected error(s) have {<error position>=<unreported error>}: $errorMap")
641641
else None
642642
}
643643

tests/neg/literals.scala

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
trait RejectedLiterals {
2+
def missingHex: Int = { 0x } // error: invalid literal number
3+
}
4+
/*
5+
// scalac: -Ywarn-octal-literal -Xfatal-warnings -deprecation
6+
trait RejectedLiterals {
7+
8+
def missingHex: Int = { 0x } // line 4: was: not reported, taken as zero
9+
10+
def leadingZeros: Int = { 01 } // line 6: no leading zero
11+
12+
def tooManyZeros: Int = { 00 } // line 8: no leading zero
13+
14+
def zeroOfNine: Int = { 09 } // line 10: no leading zero
15+
16+
def orphanDot: Int = { 9. } // line 12: ident expected
17+
18+
def zeroOfNineDot: Int = { 09. } // line 14: malformed integer, ident expected
19+
20+
def noHexFloat: Double = { 0x1.2 } // line 16: ';' expected but double literal found.
21+
22+
}
23+
24+
trait Braceless {
25+
26+
def missingHex: Int = 0x // line 22: was: not reported, taken as zero
27+
28+
def leadingZeros: Int = 01 // line 24: no leading zero
29+
30+
def tooManyZeros: Int = 00 // line 26: no leading zero
31+
32+
def zeroOfNine: Int = 09 // line 28: no leading zero
33+
34+
def orphanDot: Int = 9. // line 30: ident expected
35+
36+
def zeroOfNineDot: Int = 09. // line 32: malformed integer, ident expected
37+
38+
def noHexFloat: Double = 0x1.2 // line 34: ';' expected but double literal found.
39+
}
40+
41+
trait MoreSadness {
42+
43+
def tooTiny: Float = { 0.7e-45f } // floating point number too small
44+
45+
def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small
46+
47+
def tooHuge: Float = { 3.4028236E38f } // floating point number too large
48+
49+
def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large
50+
}
51+
52+
trait Lengthy {
53+
54+
def bad = 1l
55+
56+
def worse = 123l
57+
}
58+
*/

tests/neg/t6124.check

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -46,46 +46,10 @@
4646
24 | val x5 = 0_x52 // error
4747
| ^
4848
| trailing separator is not allowed
49-
-- Error: tests/neg/t6124.scala:25:13 ----------------------------------------------------------------------------------
50-
25 | val x6 = 0x_52 // error
51-
| ^
52-
| leading separator is not allowed
53-
-- Error: tests/neg/t6124.scala:26:14 ----------------------------------------------------------------------------------
49+
-- Error: tests/neg/t6124.scala:26:13 ----------------------------------------------------------------------------------
5450
26 | val x8 = 0x52_ // error
55-
| ^
56-
| trailing separator is not allowed
57-
-- Error: tests/neg/t6124.scala:27:11 ----------------------------------------------------------------------------------
58-
27 | val x9 = 0_52 // error
59-
| ^
60-
| Numbers may not have a leading zero.
61-
-- Error: tests/neg/t6124.scala:28:12 ----------------------------------------------------------------------------------
62-
28 | val x10 = 052 // error
63-
| ^
64-
| Numbers may not have a leading zero.
65-
-- Error: tests/neg/t6124.scala:29:12 ----------------------------------------------------------------------------------
66-
29 | val x11 = 0_0.52 // error
67-
| ^
68-
| Numbers may not have a leading zero.
69-
-- Error: tests/neg/t6124.scala:30:12 ----------------------------------------------------------------------------------
70-
30 | val x12 = 00.52 // error
71-
| ^
72-
| Numbers may not have a leading zero.
73-
-- Error: tests/neg/t6124.scala:31:12 ----------------------------------------------------------------------------------
74-
31 | val x13 = 00 // error
75-
| ^
76-
| Numbers may not have a leading zero.
77-
-- Error: tests/neg/t6124.scala:32:12 ----------------------------------------------------------------------------------
78-
32 | val x14 = 00d // error
79-
| ^
80-
| Numbers may not have a leading zero.
81-
-- Error: tests/neg/t6124.scala:33:12 ----------------------------------------------------------------------------------
82-
33 | val x15 = 00.0 // error
83-
| ^
84-
| Numbers may not have a leading zero.
85-
-- Error: tests/neg/t6124.scala:34:12 ----------------------------------------------------------------------------------
86-
34 | val x16 = 0_0 // error
87-
| ^
88-
| Numbers may not have a leading zero.
51+
| ^
52+
| trailing separator is not allowed
8953
-- Error: tests/neg/t6124.scala:12:17 ----------------------------------------------------------------------------------
9054
12 | def tooSmall = 1.0E-325 // error
9155
| ^^^^^^^^

tests/neg/t6124.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ trait T {
2222
val x3 = 52_ // error
2323

2424
val x5 = 0_x52 // error
25-
val x6 = 0x_52 // error
25+
val x6 = 0x_52
2626
val x8 = 0x52_ // error
27-
val x9 = 0_52 // error
28-
val x10 = 052 // error
29-
val x11 = 0_0.52 // error
30-
val x12 = 00.52 // error
31-
val x13 = 00 // error
32-
val x14 = 00d // error
33-
val x15 = 00.0 // error
34-
val x16 = 0_0 // error
27+
val x9 = 0_52
28+
val x10 = 052
29+
val x11 = 0_0.52
30+
val x12 = 00.52
31+
val x13 = 00
32+
val x14 = 00d
33+
val x15 = 00.0
34+
val x16 = 0_0
3535

3636
def z = 0
3737
}

tests/run/literals.check

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

tests/run/literals.scala

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,23 @@
22
// Literals
33
//############################################################################
44

5-
//############################################################################
5+
import scala.util.{Failure, Success, Try}
66

77
object Test {
88

9-
/* I add a couple of Unicode identifier tests here temporarily */
9+
/* I add a couple of Unicode identifier tests here "temporarily" */
1010

1111
def \u03b1\u03c1\u03b5\u03c4\u03b7 = "alpha rho epsilon tau eta"
1212

1313
case class GGG(i: Int) {
1414
def \u03b1\u03b1(that: GGG) = i + that.i
1515
}
1616

17-
def check_success[a](name: String, closure: => a, expected: a): Unit = {
18-
print("test " + name)
19-
try {
20-
val actual: a = closure
21-
if (actual == expected) {
22-
print(" was successful");
23-
} else {
24-
print(" failed: expected "+ expected +", found "+ actual);
25-
}
26-
} catch {
27-
case exception: Throwable => {
28-
print(" raised exception " + exception);
29-
}
17+
def check_success[A](name: String, closure: => A, expected: A): Unit =
18+
Try(closure) match {
19+
case Success(actual) => assert(actual == expected, s"test $name failed: expected $expected, found $actual")
20+
case Failure(error) => throw new AssertionError(s"test $name raised exception $error")
3021
}
31-
println
32-
}
3322

3423
def main(args: Array[String]): Unit = {
3524
// char
@@ -39,13 +28,9 @@ object Test {
3928
check_success("\"\\141\\142\" == \"ab\"", "\141\142", "ab")
4029
check_success("\"\\0x61\\0x62\".trim() == \"x61\\0x62\"", "\0x61\0x62".substring(1), "x61\0x62")
4130

42-
println
43-
4431
// boolean
4532
check_success("(65 : Byte) == 'A'", (65: Byte) == 'A', true) // contrib #176
4633

47-
println
48-
4934
// int
5035
check_success("0X01 == 1", 0X01, 1)
5136
check_success("0x01 == 1", 0x01, 1)
@@ -67,12 +52,10 @@ object Test {
6752
check_success("0x80000000 == -2147483648", 0x80000000, -2147483648)
6853
check_success("0xffffffff == -1", 0xffffffff, -1)
6954

70-
println
71-
7255
// long
7356
check_success("1l == 1L", 1l, 1L)
7457
check_success("1L == 1l", 1L, 1l)
75-
check_success("1.asInstanceOf[Long] == 1l", 1.asInstanceOf[Long], 1l)
58+
check_success("1.asInstanceOf[Long] == 1L", 1.asInstanceOf[Long], 1L)
7659

7760
check_success("0x7fffffffffffffffL == 9223372036854775807L",
7861
0x7fffffffffffffffL, 9223372036854775807L)
@@ -81,37 +64,48 @@ object Test {
8164
check_success("0xffffffffffffffffL == -1L",
8265
0xffffffffffffffffL, -1L)
8366

84-
println
85-
8667
// see JLS at address:
8768
// http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#230798
8869

8970
// float
9071
check_success("1e1f == 10.0f", 1e1f, 10.0f)
9172
check_success(".3f == 0.3f", .3f, 0.3f)
9273
check_success("0f == 0.0f", 0f, 0.0f)
74+
check_success("0f == -0.000000000000000000e+00f", 0f, -0.000000000000000000e+00f)
75+
check_success("0f == -0.000000000000000000e+00F", 0f, -0.000000000000000000e+00F)
76+
check_success("0f == -0.0000000000000000e14f", 0f, -0.0000000000000000e14f)
77+
check_success("01.23f == 1.23f", 01.23f, 1.23f)
9378
check_success("3.14f == 3.14f", 3.14f, 3.14f)
9479
check_success("6.022e23f == 6.022e23f", 6.022e23f, 6.022e23f)
95-
check_success("09f == 9.0f", 9f, 9.0f)
80+
check_success("9f == 9.0f", 9f, 9.0f)
81+
check_success("09f == 9.0f", 09f, 9.0f)
82+
check_success("1.00000017881393421514957253748434595763683319091796875001f == 1.0000001f",
83+
1.00000017881393421514957253748434595763683319091796875001f,
84+
1.0000001f)
85+
check_success("3.4028235E38f == Float.MaxValue", 3.4028235E38f, Float.MaxValue)
9686
check_success("1.asInstanceOf[Float] == 1.0", 1.asInstanceOf[Float], 1.0f)
97-
check_success("1l.asInstanceOf[Float] == 1.0", 1l.asInstanceOf[Float], 1.0f)
98-
99-
println
87+
check_success("1L.asInstanceOf[Float] == 1.0", 1L.asInstanceOf[Float], 1.0f)
10088

10189
// double
10290
check_success("1e1 == 10.0", 1e1, 10.0)
10391
check_success(".3 == 0.3", .3, 0.3)
10492
check_success("0.0 == 0.0", 0.0, 0.0)
10593
check_success("0d == 0.0", 0d, 0.0)
106-
check_success("01.23 == 1.23", 1.23, 1.23)
94+
check_success("0d == 0.000000000000000000e+00d", 0d, 0.000000000000000000e+00d)
95+
check_success("0d == -0.000000000000000000e+00d", 0d, -0.000000000000000000e+00d)
96+
check_success("0d == -0.000000000000000000e+00D", 0d, -0.000000000000000000e+00D)
97+
check_success("0.0 == 0.000000000000000000e+00", 0.0, 0.000000000000000000e+00)
98+
check_success("0.0 == -0.000000000000000000e+00", 0.0, -0.000000000000000000e+00)
99+
check_success("1.23 == 1.23", 1.23, 1.23)
100+
check_success("01.23 == 1.23", 01.23, 1.23)
107101
check_success("01.23d == 1.23d", 1.23d, 1.23d)
108102
check_success("3.14 == 3.14", 3.14, 3.14)
109103
check_success("1e-9d == 1.0e-9", 1e-9d, 1.0e-9)
110104
check_success("1e137 == 1.0e137", 1e137, 1.0e137)
105+
check_success("1.7976931348623157e308d == Double.MaxValue", 1.7976931348623157e308d, Double.MaxValue)
111106
check_success("1.asInstanceOf[Double] == 1.0", 1.asInstanceOf[Double], 1.0)
112-
check_success("1l.asInstanceOf[Double] == 1.0", 1l.asInstanceOf[Double], 1.0)
107+
check_success("1L.asInstanceOf[Double] == 1.0", 1L.asInstanceOf[Double], 1.0)
113108

114-
println
115109
check_success("\"\".length()", "\u001a".length(), 1)
116110

117111
val ggg = GGG(1) \u03b1\u03b1 GGG(2)

0 commit comments

Comments
 (0)