From 9d5098f7759c43f7ea168365f6301d1b68bb6001 Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Thu, 29 May 2014 18:11:25 -0400 Subject: [PATCH] Add support for literal Byte and Short values. This commit reserves the [zZ] and [sS] suffixes for Byte and Short literals, respectively. These work exactly like Long literals, which were already denoted with [lL]. For example, you can say: val zero = 0Z val bytes = List(23Z, 23Z, 0Z, 0Z, 111Z, -54Z, 19Z, 17Z) This commit does not permit literal unsigned bytes, so 255Z and 0xffZ are not legal. The choice of Z may seem strange, but B will not work for hex constants (0x10B would be ambiguous) so Z seemed like a good choice. --- .../tools/nsc/ast/parser/CommonTokens.scala | 2 + .../scala/tools/nsc/ast/parser/Parsers.scala | 10 +++-- .../scala/tools/nsc/ast/parser/Scanners.scala | 37 ++++++++++++++----- .../scala/tools/nsc/javac/JavaScanners.scala | 17 ++++++++- test/files/run/literals.check | 16 ++++++++ test/files/run/literals.scala | 22 +++++++++++ 6 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala index 5fcb02814b36..2582f432c41a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala @@ -20,6 +20,8 @@ abstract class CommonTokens { final val FLOATLIT = 4 final val DOUBLELIT = 5 final val STRINGLIT = 6 + final val BYTELIT = 12 + final val SHORTLIT = 13 /** keywords */ final val NEW = 20 diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 8d810d456e60..b9d44a91c2b1 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -643,7 +643,7 @@ self => def isDefIntro = isTemplateIntro || isDclIntro def isNumericLit: Boolean = in.token match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => true + case BYTELIT | SHORTLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => true case _ => false } @@ -659,7 +659,7 @@ self => def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw def isLiteralToken(token: Token) = token match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | + case BYTELIT | SHORTLIT | CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => true case _ => false } @@ -1186,6 +1186,8 @@ self => case LONGLIT => in.intVal(isNegated) case FLOATLIT => in.floatVal(isNegated).toFloat case DOUBLELIT => in.floatVal(isNegated) + case BYTELIT => in.intVal(isNegated).toByte + case SHORTLIT => in.intVal(isNegated).toShort case STRINGLIT | STRINGPART => in.strVal.intern() case TRUE => true case FALSE => false @@ -1958,7 +1960,7 @@ self => case IDENTIFIER | BACKQUOTED_IDENT | THIS => val t = stableId() in.token match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => + case BYTELIT | SHORTLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(nme.MINUS) => return literal(isNegated = true, inPattern = true, start = start) @@ -1977,7 +1979,7 @@ self => case USCORE => in.nextToken() atPos(start, start) { Ident(nme.WILDCARD) } - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | + case BYTELIT | SHORTLIT | CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => literal(inPattern = true) case LPAREN => diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 9ebc94b5fc91..328c10448b2f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -594,7 +594,7 @@ trait Scanners extends ScannersCommon { /** Can token end a statement? */ def inLastOfStat(token: Token) = token match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | + case CHARLIT | BYTELIT | SHORTLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => true @@ -911,8 +911,12 @@ trait Scanners extends ScannersCommon { } else { var value: Long = 0 val divider = if (base == 10) 1 else 2 - val limit: Long = - if (token == LONGLIT) Long.MaxValue else Int.MaxValue + val limit: Long = token match { + case LONGLIT => Long.MaxValue + case BYTELIT => Byte.MaxValue + case SHORTLIT => Short.MaxValue + case _ => Int.MaxValue + } var i = 0 val len = strVal.length while (i < len) { @@ -996,7 +1000,6 @@ trait Scanners extends ScannersCommon { } def restOfUncertainToken() = { def isEfd = ch match { case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => true ; case _ => false } - def isL = ch match { case 'l' | 'L' => true ; case _ => false } if (base <= 10 && isEfd) getFraction() @@ -1005,17 +1008,25 @@ trait Scanners extends ScannersCommon { // as soon as a 0 is read in `case '0'` of method fetchToken. if (base == 8 && notSingleZero) syntaxError("Non-zero integral values may not have a leading zero.") setStrVal() - if (isL) { - nextChar() - token = LONGLIT + ch match { + case 'l' | 'L' => + nextChar() + token = LONGLIT + case 'z' | 'Z' => + nextChar() + token = BYTELIT + case 's' | 'S' => + nextChar() + token = SHORTLIT + case _ => + checkNoLetter() } - else checkNoLetter() } } - if (base > 10 || ch != '.') + if (base > 10 || ch != '.') { restOfUncertainToken() - else { + } else { val lookahead = lookaheadReader val c = lookahead.getc() @@ -1095,6 +1106,10 @@ trait Scanners extends ScannersCommon { "int(" + intVal + ")" case LONGLIT => "long(" + intVal + ")" + case BYTELIT => + "byte(" + intVal + ")" + case SHORTLIT => + "short(" + intVal + ")" case FLOATLIT => "float(" + floatVal + ")" case DOUBLELIT => @@ -1212,6 +1227,8 @@ trait Scanners extends ScannersCommon { case CHARLIT => "character literal" case INTLIT => "integer literal" case LONGLIT => "long literal" + case BYTELIT => "byte literal" + case SHORTLIT => "short literal" case FLOATLIT => "float literal" case DOUBLELIT => "double literal" case STRINGLIT | STRINGPART | INTERPOLATIONID => "string literal" diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index ac86dfd66510..f14965b8716f 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -150,6 +150,8 @@ trait JavaScanners extends ast.parser.ScannersCommon { case INTLIT => "integer literal" case LONGLIT => "long literal" case STRINGLIT => "string literal" + case BYTELIT => "byte literal" + case SHORTLIT => "short literal" case EOF => "eof" case ERROR => "something" case AMP => "`&'" @@ -728,8 +730,13 @@ trait JavaScanners extends ast.parser.ScannersCommon { } else { var value: Long = 0 val divider = if (base == 10) 1 else 2 - val limit: Long = - if (token == LONGLIT) Long.MaxValue else Int.MaxValue + val limit: Long = token match { + case BYTELIT => Byte.MaxValue + case SHORTLIT => Short.MaxValue + case LONGLIT => Long.MaxValue + case _ => Int.MaxValue + } + var i = 0 val len = name.length while (i < len) { @@ -804,6 +811,12 @@ trait JavaScanners extends ast.parser.ScannersCommon { if (in.ch == 'l' || in.ch == 'L') { in.next() token = LONGLIT + } else if (in.ch == 'z' || in.ch == 'Z') { + in.next() + token = BYTELIT + } else if (in.ch == 's' || in.ch == 'S') { + in.next() + token = SHORTLIT } } diff --git a/test/files/run/literals.check b/test/files/run/literals.check index 62c5fd68ae86..80462c1d06d0 100644 --- a/test/files/run/literals.check +++ b/test/files/run/literals.check @@ -7,6 +7,22 @@ test "\0x61\0x62".trim() == "x61\0x62" was successful test (65 : Byte) == 'A' was successful +test 1z == 1 was successful +test -1z == -1 was successful +test 1Z == 1 was successful +test -1Z == -1 was successful +test 0xffZ == -1 was successful +test 0xFFz == -1 was successful +test 0x0aZ == 0xAz was successful + +test 1s == 1 was successful +test -1s == -1 was successful +test 1S == 1 was successful +test -1S == -1 was successful +test 0xffffS == -1 was successful +test 0xFFFFs == -1 was successful +test 0x0aS == 0xAs was successful + test 0X01 == 1 was successful test 0x01 == 1 was successful test 0x10 == 16 was successful diff --git a/test/files/run/literals.scala b/test/files/run/literals.scala index 5f23e6b49270..ff2a0d990d31 100644 --- a/test/files/run/literals.scala +++ b/test/files/run/literals.scala @@ -46,6 +46,28 @@ object Test { println + // byte + check_success[Byte]("1z == 1", 1z, 1.toByte) + check_success[Byte]("-1z == -1", -1z, -1.toByte) + check_success[Byte]("1Z == 1", 1Z, 1.toByte) + check_success[Byte]("-1Z == -1", -1Z, -1.toByte) + check_success[Byte]("0xffZ == -1", 0xffZ, -1.toByte) + check_success[Byte]("0xFFz == -1", 0xFFz, -1.toByte) + check_success[Byte]("0x0aZ == 0xAz", 0x0aZ, 0xAz) + + println + + // short + check_success[Short]("1s == 1", 1s, 1.toShort) + check_success[Short]("-1s == -1", -1s, -1.toShort) + check_success[Short]("1S == 1", 1S, 1.toShort) + check_success[Short]("-1S == -1", -1S, -1.toShort) + check_success[Short]("0xffffS == -1", 0xffffS, -1.toShort) + check_success[Short]("0xFFFFs == -1", 0xFFFFs, -1.toShort) + check_success[Short]("0x0aS == 0xAs", 0x0aS, 0xAs) + + println + // int check_success("0X01 == 1", 0X01, 1) check_success("0x01 == 1", 0x01, 1)