Skip to content

Accept 0x_42, reject 0x #8269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,11 @@ object Scanners {

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

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

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

Expand Down Expand Up @@ -706,28 +705,18 @@ object Scanners {
getOperatorRest()
}
case '0' =>
def fetchZero() = {
putChar(ch)
def fetchLeadingZero(): Unit = {
nextChar()
if (ch == 'x' || ch == 'X') {
nextChar()
base = 16
if (isNumberSeparator(ch))
errorButContinue("leading separator is not allowed", offset + 2)
ch match {
case 'x' | 'X' => base = 16 ; nextChar()
//case 'b' | 'B' => base = 2 ; nextChar()
case _ => base = 10 ; putChar('0')
}
else {
/**
* What should leading 0 be in the future? It is potentially dangerous
* to let it be base-10 because of history. Should it be an error? Is
* there a realistic situation where one would need it?
*/
if (isDigit(ch) || (isNumberSeparator(ch) && isDigit(lookaheadChar())))
error("Numbers may not have a leading zero.")
base = 10
}
getNumber()
if (base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0)
error("invalid literal number")
}
fetchZero()
fetchLeadingZero()
getNumber()
case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
base = 10
getNumber()
Expand Down
8 changes: 4 additions & 4 deletions compiler/test/dotty/tools/vulpix/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -633,11 +633,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
lazy val actualErrors = reporters.foldLeft(0)(_ + _.errorCount)
def hasMissingAnnotations = getMissingExpectedErrors(errorMap, reporters.iterator.flatMap(_.errors))

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

Expand Down
58 changes: 58 additions & 0 deletions tests/neg/literals.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
trait RejectedLiterals {
def missingHex: Int = { 0x } // error: invalid literal number
}
/*
// scalac: -Ywarn-octal-literal -Xfatal-warnings -deprecation
trait RejectedLiterals {

def missingHex: Int = { 0x } // line 4: was: not reported, taken as zero

def leadingZeros: Int = { 01 } // line 6: no leading zero

def tooManyZeros: Int = { 00 } // line 8: no leading zero

def zeroOfNine: Int = { 09 } // line 10: no leading zero

def orphanDot: Int = { 9. } // line 12: ident expected

def zeroOfNineDot: Int = { 09. } // line 14: malformed integer, ident expected

def noHexFloat: Double = { 0x1.2 } // line 16: ';' expected but double literal found.

}

trait Braceless {

def missingHex: Int = 0x // line 22: was: not reported, taken as zero

def leadingZeros: Int = 01 // line 24: no leading zero

def tooManyZeros: Int = 00 // line 26: no leading zero

def zeroOfNine: Int = 09 // line 28: no leading zero

def orphanDot: Int = 9. // line 30: ident expected

def zeroOfNineDot: Int = 09. // line 32: malformed integer, ident expected

def noHexFloat: Double = 0x1.2 // line 34: ';' expected but double literal found.
}

trait MoreSadness {

def tooTiny: Float = { 0.7e-45f } // floating point number too small

def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small

def tooHuge: Float = { 3.4028236E38f } // floating point number too large

def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large
}

trait Lengthy {

def bad = 1l

def worse = 123l
}
*/
42 changes: 3 additions & 39 deletions tests/neg/t6124.check
Original file line number Diff line number Diff line change
Expand Up @@ -46,46 +46,10 @@
24 | val x5 = 0_x52 // error
| ^
| trailing separator is not allowed
-- Error: tests/neg/t6124.scala:25:13 ----------------------------------------------------------------------------------
25 | val x6 = 0x_52 // error
| ^
| leading separator is not allowed
-- Error: tests/neg/t6124.scala:26:14 ----------------------------------------------------------------------------------
-- Error: tests/neg/t6124.scala:26:13 ----------------------------------------------------------------------------------
26 | val x8 = 0x52_ // error
| ^
| trailing separator is not allowed
-- Error: tests/neg/t6124.scala:27:11 ----------------------------------------------------------------------------------
27 | val x9 = 0_52 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:28:12 ----------------------------------------------------------------------------------
28 | val x10 = 052 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:29:12 ----------------------------------------------------------------------------------
29 | val x11 = 0_0.52 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:30:12 ----------------------------------------------------------------------------------
30 | val x12 = 00.52 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:31:12 ----------------------------------------------------------------------------------
31 | val x13 = 00 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:32:12 ----------------------------------------------------------------------------------
32 | val x14 = 00d // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:33:12 ----------------------------------------------------------------------------------
33 | val x15 = 00.0 // error
| ^
| Numbers may not have a leading zero.
-- Error: tests/neg/t6124.scala:34:12 ----------------------------------------------------------------------------------
34 | val x16 = 0_0 // error
| ^
| Numbers may not have a leading zero.
| ^
| trailing separator is not allowed
-- Error: tests/neg/t6124.scala:12:17 ----------------------------------------------------------------------------------
12 | def tooSmall = 1.0E-325 // error
| ^^^^^^^^
Expand Down
18 changes: 9 additions & 9 deletions tests/neg/t6124.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ trait T {
val x3 = 52_ // error

val x5 = 0_x52 // error
val x6 = 0x_52 // error
val x6 = 0x_52
val x8 = 0x52_ // error
val x9 = 0_52 // error
val x10 = 052 // error
val x11 = 0_0.52 // error
val x12 = 00.52 // error
val x13 = 00 // error
val x14 = 00d // error
val x15 = 00.0 // error
val x16 = 0_0 // error
val x9 = 0_52
val x10 = 052
val x11 = 0_0.52
val x12 = 00.52
val x13 = 00
val x14 = 00d
val x15 = 00.0
val x16 = 0_0

def z = 0
}
55 changes: 0 additions & 55 deletions tests/run/literals.check

This file was deleted.

60 changes: 27 additions & 33 deletions tests/run/literals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,23 @@
// Literals
//############################################################################

//############################################################################
import scala.util.{Failure, Success, Try}

object Test {

/* I add a couple of Unicode identifier tests here temporarily */
/* I add a couple of Unicode identifier tests here "temporarily" */

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

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

def check_success[a](name: String, closure: => a, expected: a): Unit = {
print("test " + name)
try {
val actual: a = closure
if (actual == expected) {
print(" was successful");
} else {
print(" failed: expected "+ expected +", found "+ actual);
}
} catch {
case exception: Throwable => {
print(" raised exception " + exception);
}
def check_success[A](name: String, closure: => A, expected: A): Unit =
Try(closure) match {
case Success(actual) => assert(actual == expected, s"test $name failed: expected $expected, found $actual")
case Failure(error) => throw new AssertionError(s"test $name raised exception $error")
}
println
}

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

println

// boolean
check_success("(65 : Byte) == 'A'", (65: Byte) == 'A', true) // contrib #176

println

// int
check_success("0X01 == 1", 0X01, 1)
check_success("0x01 == 1", 0x01, 1)
Expand All @@ -67,12 +52,10 @@ object Test {
check_success("0x80000000 == -2147483648", 0x80000000, -2147483648)
check_success("0xffffffff == -1", 0xffffffff, -1)

println

// long
check_success("1l == 1L", 1l, 1L)
check_success("1L == 1l", 1L, 1l)
check_success("1.asInstanceOf[Long] == 1l", 1.asInstanceOf[Long], 1l)
check_success("1.asInstanceOf[Long] == 1L", 1.asInstanceOf[Long], 1L)

check_success("0x7fffffffffffffffL == 9223372036854775807L",
0x7fffffffffffffffL, 9223372036854775807L)
Expand All @@ -81,37 +64,48 @@ object Test {
check_success("0xffffffffffffffffL == -1L",
0xffffffffffffffffL, -1L)

println

// see JLS at address:
// http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#230798

// float
check_success("1e1f == 10.0f", 1e1f, 10.0f)
check_success(".3f == 0.3f", .3f, 0.3f)
check_success("0f == 0.0f", 0f, 0.0f)
check_success("0f == -0.000000000000000000e+00f", 0f, -0.000000000000000000e+00f)
check_success("0f == -0.000000000000000000e+00F", 0f, -0.000000000000000000e+00F)
check_success("0f == -0.0000000000000000e14f", 0f, -0.0000000000000000e14f)
check_success("01.23f == 1.23f", 01.23f, 1.23f)
check_success("3.14f == 3.14f", 3.14f, 3.14f)
check_success("6.022e23f == 6.022e23f", 6.022e23f, 6.022e23f)
check_success("09f == 9.0f", 9f, 9.0f)
check_success("9f == 9.0f", 9f, 9.0f)
check_success("09f == 9.0f", 09f, 9.0f)
check_success("1.00000017881393421514957253748434595763683319091796875001f == 1.0000001f",
1.00000017881393421514957253748434595763683319091796875001f,
1.0000001f)
check_success("3.4028235E38f == Float.MaxValue", 3.4028235E38f, Float.MaxValue)
check_success("1.asInstanceOf[Float] == 1.0", 1.asInstanceOf[Float], 1.0f)
check_success("1l.asInstanceOf[Float] == 1.0", 1l.asInstanceOf[Float], 1.0f)

println
check_success("1L.asInstanceOf[Float] == 1.0", 1L.asInstanceOf[Float], 1.0f)

// double
check_success("1e1 == 10.0", 1e1, 10.0)
check_success(".3 == 0.3", .3, 0.3)
check_success("0.0 == 0.0", 0.0, 0.0)
check_success("0d == 0.0", 0d, 0.0)
check_success("01.23 == 1.23", 1.23, 1.23)
check_success("0d == 0.000000000000000000e+00d", 0d, 0.000000000000000000e+00d)
check_success("0d == -0.000000000000000000e+00d", 0d, -0.000000000000000000e+00d)
check_success("0d == -0.000000000000000000e+00D", 0d, -0.000000000000000000e+00D)
check_success("0.0 == 0.000000000000000000e+00", 0.0, 0.000000000000000000e+00)
check_success("0.0 == -0.000000000000000000e+00", 0.0, -0.000000000000000000e+00)
check_success("1.23 == 1.23", 1.23, 1.23)
check_success("01.23 == 1.23", 01.23, 1.23)
check_success("01.23d == 1.23d", 1.23d, 1.23d)
check_success("3.14 == 3.14", 3.14, 3.14)
check_success("1e-9d == 1.0e-9", 1e-9d, 1.0e-9)
check_success("1e137 == 1.0e137", 1e137, 1.0e137)
check_success("1.7976931348623157e308d == Double.MaxValue", 1.7976931348623157e308d, Double.MaxValue)
check_success("1.asInstanceOf[Double] == 1.0", 1.asInstanceOf[Double], 1.0)
check_success("1l.asInstanceOf[Double] == 1.0", 1l.asInstanceOf[Double], 1.0)
check_success("1L.asInstanceOf[Double] == 1.0", 1L.asInstanceOf[Double], 1.0)

println
check_success("\"\".length()", "\u001a".length(), 1)

val ggg = GGG(1) \u03b1\u03b1 GGG(2)
Expand Down