/* NSC -- new Scala compiler * Copyright 2005-2013 LAMP/EPFL * @author James Iry */ // $Id$ package scala package tools.nsc.settings /** * 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 } } /** * Factory methods for producing ScalaVersions */ object ScalaVersion { private val dot = """\.""" private val dash = "-" private val vchar = """\d""" //"[^-+.]" private val vpat = s"(?s)($vchar+)(?:$dot($vchar+)(?:$dot($vchar+)(?:$dash(.*))?)?)?".r private val rcpat = """(?i)rc(\d*)""".r private val mspat = """(?i)m(\d*)""".r def apply(versionString: String, errorHandler: String => Unit): ScalaVersion = { def error() = errorHandler( s"Bad version (${versionString}) not major[.minor[.revision[-suffix]]]" ) def toInt(s: String) = s match { case null | "" => 0 case _ => s.toInt } def toBuild(s: String) = s match { case null | "FINAL" => Final case rcpat(i) => RC(toInt(i)) case mspat(i) => Milestone(toInt(i)) case _ /* | "" */ => Development(s) } versionString match { case "none" => NoScalaVersion case "" => NoScalaVersion case "any" => AnyScalaVersion case vpat(majorS, minorS, revS, buildS) => SpecificScalaVersion(toInt(majorS), toInt(minorS), toInt(revS), toBuild(buildS)) case _ => error() ; AnyScalaVersion } } def apply(versionString: String): ScalaVersion = apply(versionString, msg => throw new NumberFormatException(msg)) /** * The version of the compiler running now */ val current = apply(util.Properties.versionNumberString) /** * The 2.8.0 version. */ val twoDotEight = SpecificScalaVersion(2, 8, 0, Final) } /** * 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 } /** * A development, test, integration, 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 final */ 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 } }