diff --git a/project/Sbt.scala b/project/Sbt.scala index 09ea8c0ee..1dd1a4c6c 100644 --- a/project/Sbt.scala +++ b/project/Sbt.scala @@ -52,7 +52,7 @@ object Sbt extends Build /* **** Utilities **** */ lazy val controlSub = baseProject(utilPath / "control", "Control") - lazy val collectionSub = testedBaseProject(utilPath / "collection", "Collections") + lazy val collectionSub = testedBaseProject(utilPath / "collection", "Collections") settings( Util.keywordsSettings: _* ) // The API for forking, combining, and doing I/O with system processes lazy val processSub = baseProject(utilPath / "process", "Process") dependsOn(ioSub % "test->test") // Path, IO (formerly FileUtilities), NameFilter and other I/O utility classes diff --git a/project/Util.scala b/project/Util.scala index 9cdc6de2a..ac7f8e6f6 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -6,6 +6,8 @@ object Util { val ExclusiveTest = Tags.Tag("exclusive-test") lazy val componentID = SettingKey[Option[String]]("component-id") + lazy val scalaKeywords = TaskKey[Set[String]]("scala-keywords") + lazy val generateKeywords = TaskKey[File]("generateKeywords") def inAll(projects: => Seq[ProjectReference], key: ScopedSetting[Task[Unit]]): Project.Initialize[Task[Unit]] = inAllProjects(projects, key) { deps => nop dependsOn( deps : _*) } @@ -17,7 +19,6 @@ object Util refs map ( ref => (key in ref).? ) joinWith(_ flatMap { x => x}) } - def noPublish(p: Project) = p.copy(settings = noRemotePublish(p.settings)) def noRemotePublish(in: Seq[Setting[_]]) = in filterNot { s => s.key == deliver || s.key == publish } @@ -113,6 +114,30 @@ object Util val all = tags.getOrElse(Tags.All, 0) exclusive == 0 || all == 1 } + + def getScalaKeywords: Set[String] = + { + val g = new scala.tools.nsc.Global(new scala.tools.nsc.Settings) + g.nme.keywords.map(_.toString) + } + def writeScalaKeywords(base: File, keywords: Set[String]): File = + { + val init = keywords.map(tn => '"' + tn + '"').mkString("Set(", ", ", ")") + val ObjectName = "ScalaKeywords" + val keywordsSrc = +"""package sbt +object %s { + val values = %s +}""".format(ObjectName, init) + val out = base / (ObjectName + ".scala") + IO.write(out, keywordsSrc) + out + } + def keywordsSettings: Seq[Setting[_]] = inConfig(Compile)(Seq( + scalaKeywords := getScalaKeywords, + generateKeywords <<= (sourceManaged, scalaKeywords) map writeScalaKeywords, + sourceGenerators <+= generateKeywords map (x => Seq(x)) + )) } object Common { diff --git a/util/collection/Util.scala b/util/collection/Util.scala index a886c233d..c36bb6443 100644 --- a/util/collection/Util.scala +++ b/util/collection/Util.scala @@ -22,4 +22,14 @@ object Util } def pairID[A,B] = (a: A, b: B) => (a,b) + + private[this] lazy val Hypen = """-(\p{javaLowerCase})""".r + def hypenToCamel(s: String): String = + Hypen.replaceAllIn(s, _.group(1).toUpperCase) + + private[this] lazy val Camel = """(\p{javaLowerCase})(\p{javaUpperCase})""".r + def camelToHypen(s: String): String = + Camel.replaceAllIn(s, m => m.group(1) + "-" + m.group(2).toLowerCase) + + def quoteIfKeyword(s: String): String = if(ScalaKeywords.values(s)) '`' + s + '`' else s } diff --git a/util/complete/Parsers.scala b/util/complete/Parsers.scala index 5e4d46bc1..f289cc6ac 100644 --- a/util/complete/Parsers.scala +++ b/util/complete/Parsers.scala @@ -22,11 +22,17 @@ trait Parsers lazy val Letter = charClass(_.isLetter, "letter") def IDStart = Letter lazy val IDChar = charClass(isIDChar, "ID character") - lazy val ID = IDStart ~ IDChar.* map { case x ~ xs => (x +: xs).mkString } + lazy val ID = identifier(IDStart, IDChar) lazy val OpChar = charClass(isOpChar, "symbol") lazy val Op = OpChar.+.string lazy val OpOrID = ID | Op + lazy val ScalaIDChar = charClass(isScalaIDChar, "Scala identifier character") + lazy val ScalaID = identifier(IDStart, ScalaIDChar) + + def identifier(start: Parser[Char], rep: Parser[Char]): Parser[String] = + start ~ rep.* map { case x ~ xs => (x +: xs).mkString } + def opOrIDSpaced(s: String): Parser[Char] = if(DefaultParsers.matches(ID, s)) OpChar | SpaceClass @@ -37,7 +43,8 @@ trait Parsers def isOpChar(c: Char) = !isDelimiter(c) && isOpType(getType(c)) def isOpType(cat: Int) = cat match { case MATH_SYMBOL | OTHER_SYMBOL | DASH_PUNCTUATION | OTHER_PUNCTUATION | MODIFIER_SYMBOL | CURRENCY_SYMBOL => true; case _ => false } - def isIDChar(c: Char) = c.isLetterOrDigit || c == '-' || c == '_' + def isIDChar(c: Char) = isScalaIDChar(c) || c == '-' + def isScalaIDChar(c: Char) = c.isLetterOrDigit || c == '_' def isDelimiter(c: Char) = c match { case '`' | '\'' | '\"' | /*';' | */',' | '.' => true ; case _ => false } lazy val NotSpaceClass = charClass(!_.isWhitespace, "non-whitespace character")