diff options
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaSettings.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaVersion.scala | 183 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/Settings.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 5 |
4 files changed, 199 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index aab2942bd..af2e42b77 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -66,7 +66,8 @@ class ScalaSettings extends Settings.SettingGroup { val logFreeTerms = BooleanSetting("-Xlog-free-terms", "Print a message when reification creates a free term.") val logFreeTypes = BooleanSetting("-Xlog-free-types", "Print a message when reification resorts to generating a free type.") val maxClassfileName = IntSetting("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, 72 to 255) - val Xmigration28 = BooleanSetting("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.") + val Xmigration = VersionSetting("-Xmigration", "Warn about constructs whose behavior may have changed since version.") + val Xsource = VersionSetting("-Xsource", "Treat compiler input as Scala source for the specified version.") val Xnojline = BooleanSetting("-Xnojline", "Do not use JLine for editing.") val Xverify = BooleanSetting("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)") val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.") diff --git a/src/dotty/tools/dotc/config/ScalaVersion.scala b/src/dotty/tools/dotc/config/ScalaVersion.scala new file mode 100644 index 000000000..7d4585441 --- /dev/null +++ b/src/dotty/tools/dotc/config/ScalaVersion.scala @@ -0,0 +1,183 @@ +/* @author James Iry + */ +package dotty.tools.dotc.config + +import scala.util.{Try, Success, Failure} + +/** + * Represents a single Scala version in a manner that + * supports easy comparison and sorting. + */ +sealed abstract class ScalaVersion extends Ordered[ScalaVersion] { + def unparse: String +} + +/** + * A scala version that sorts higher than all actual versions + */ +case object NoScalaVersion extends ScalaVersion { + def unparse = "none" + + def compare(that: ScalaVersion): Int = that match { + case NoScalaVersion => 0 + case _ => 1 + } +} + +/** + * A specific Scala version, not one of the magic min/max versions. An SpecificScalaVersion + * may or may not be a released version - i.e. this same class is used to represent + * final, release candidate, milestone, and development builds. The build argument is used + * to segregate builds + */ +case class SpecificScalaVersion(major: Int, minor: Int, rev: Int, build: ScalaBuild) extends ScalaVersion { + def unparse = s"${major}.${minor}.${rev}.${build.unparse}" + + def compare(that: ScalaVersion): Int = that match { + case SpecificScalaVersion(thatMajor, thatMinor, thatRev, thatBuild) => + // this could be done more cleanly by importing scala.math.Ordering.Implicits, but we have to do these + // comparisons a lot so I'm using brute force direct style code + if (major < thatMajor) -1 + else if (major > thatMajor) 1 + else if (minor < thatMinor) -1 + else if (minor > thatMinor) 1 + else if (rev < thatRev) -1 + else if (rev > thatRev) 1 + else build compare thatBuild + case AnyScalaVersion => 1 + case NoScalaVersion => -1 + } +} + +/** + * A Scala version that sorts lower than all actual versions + */ +case object AnyScalaVersion extends ScalaVersion { + def unparse = "any" + + def compare(that: ScalaVersion): Int = that match { + case AnyScalaVersion => 0 + case _ => -1 + } +} + +/** + * Methods for parsing ScalaVersions + */ +object ScalaVersion { + private val dot = "\\." + private val dash = "\\-" + private def not(s:String) = s"[^${s}]" + private val R = s"((${not(dot)}*)(${dot}(${not(dot)}*)(${dot}(${not(dash)}*)(${dash}(.*))?)?)?)".r + + def parse(versionString : String): Try[ScalaVersion] = { + def failure = Failure(new NumberFormatException( + s"There was a problem parsing ${versionString}. " + + "Versions should be in the form major[.minor[.revision]] " + + "where each part is a positive number, as in 2.10.1. " + + "The minor and revision parts are optional." + )) + + def toInt(s: String) = s match { + case null | "" => 0 + case _ => s.toInt + } + + def isInt(s: String) = Try(toInt(s)).isSuccess + + import ScalaBuild._ + + def toBuild(s: String) = s match { + case null | "FINAL" => Final + case s if (s.toUpperCase.startsWith("RC") && isInt(s.substring(2))) => RC(toInt(s.substring(2))) + case s if (s.toUpperCase.startsWith("M") && isInt(s.substring(1))) => Milestone(toInt(s.substring(1))) + case _ => Development(s) + } + + try versionString match { + case "" | "any" => Success(AnyScalaVersion) + case "none" => Success(NoScalaVersion) + case R(_, majorS, _, minorS, _, revS, _, buildS) => + Success(SpecificScalaVersion(toInt(majorS), toInt(minorS), toInt(revS), toBuild(buildS))) + case _ => failure + } catch { + case e: NumberFormatException => failure + } + } + + /** + * The version of the compiler running now + */ + val current = parse(util.Properties.versionNumberString).get +} + +/** + * Represents the data after the dash in major.minor.rev-build + */ +abstract class ScalaBuild extends Ordered[ScalaBuild] { + /** + * Return a version of this build information that can be parsed back into the + * same ScalaBuild + */ + def unparse: String +} + +object ScalaBuild { + + /** A development, test, nightly, snapshot or other "unofficial" build + */ + case class Development(id: String) extends ScalaBuild { + def unparse = s"-${id}" + + def compare(that: ScalaBuild) = that match { + // sorting two development builds based on id is reasonably valid for two versions created with the same schema + // otherwise it's not correct, but since it's impossible to put a total ordering on development build versions + // this is a pragmatic compromise + case Development(thatId) => id compare thatId + // assume a development build is newer than anything else, that's not really true, but good luck + // mapping development build versions to other build types + case _ => 1 + } + } + + /** A final build + */ + case object Final extends ScalaBuild { + def unparse = "" + + def compare(that: ScalaBuild) = that match { + case Final => 0 + // a final is newer than anything other than a development build or another final + case Development(_) => -1 + case _ => 1 + } + } + + /** A candidate for final release + */ + case class RC(n: Int) extends ScalaBuild { + def unparse = s"-RC${n}" + + def compare(that: ScalaBuild) = that match { + // compare two rcs based on their RC numbers + case RC(thatN) => n - thatN + // an rc is older than anything other than a milestone or another rc + case Milestone(_) => 1 + case _ => -1 + } + } + + /** An intermediate release + */ + case class Milestone(n: Int) extends ScalaBuild { + def unparse = s"-M${n}" + + def compare(that: ScalaBuild) = that match { + // compare two milestones based on their milestone numbers + case Milestone(thatN) => n - thatN + // a milestone is older than anything other than another milestone + case _ => -1 + + } + } +} diff --git a/src/dotty/tools/dotc/config/Settings.scala b/src/dotty/tools/dotc/config/Settings.scala index 17d4d6712..531c49bfb 100644 --- a/src/dotty/tools/dotc/config/Settings.scala +++ b/src/dotty/tools/dotc/config/Settings.scala @@ -18,6 +18,7 @@ object Settings { val IntTag = ClassTag.Int val StringTag = ClassTag(classOf[String]) val ListTag = ClassTag(classOf[List[_]]) + val VersionTag = ClassTag(classOf[ScalaVersion]) class SettingsState(initialValues: Seq[Any]) { private var values = ArrayBuffer(initialValues: _*) @@ -132,6 +133,11 @@ object Settings { case _: NumberFormatException => fail(s"$arg2 is not an integer argument for $name", args2) } + case (VersionTag, _) => + ScalaVersion.parse(argRest) match { + case Success(v) => update(v, args) + case Failure(ex) => fail(ex.getMessage, args) + } case (_, Nil) => missingArg } @@ -246,5 +252,8 @@ object Settings { def PrefixSetting(name: String, pre: String, descr: String): Setting[List[String]] = publish(Setting(name, descr, Nil, prefix = pre)) + + def VersionSetting(name: String, descr: String, default: ScalaVersion = NoScalaVersion): Setting[ScalaVersion] = + publish(Setting(name, descr, default)) } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 286d1437f..f20882ce4 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -107,6 +107,10 @@ class Definitions { lazy val JavaPackageVal = ctx.requiredPackage("java") lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang") + // fundamental modules + lazy val SysPackage = ctx.requiredModule("scala.sys.package") + def Sys_error = ctx.requiredMethod(SysPackage.moduleClass.asClass, nme.error) + /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) * because after erasure the Any and AnyVal references get remapped to the Object methods * which would result in a double binding assertion failure. @@ -292,6 +296,7 @@ class Definitions { lazy val ScalaSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaSignature") lazy val ScalaLongSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaLongSignature") lazy val DeprecatedAnnot = ctx.requiredClass("scala.deprecated") + lazy val MigrationAnnot = ctx.requiredClass("scala.migration") lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault") lazy val ThrowsAnnot = ctx.requiredClass("scala.throws") lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked") |