diff options
author | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-10-10 12:29:01 +0200 |
---|---|---|
committer | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-10-10 12:29:01 +0200 |
commit | 3fb580276af6bc12861de42c0115c04549c98177 (patch) | |
tree | ac358d8d558474c965020572196897e3a3e37b98 /src/main/scala | |
parent | 7ccabd803ca26cde46c970c7fea45d59b7c54b3d (diff) | |
download | sbt-boilerplate-3fb580276af6bc12861de42c0115c04549c98177.tar.gz sbt-boilerplate-3fb580276af6bc12861de42c0115c04549c98177.tar.bz2 sbt-boilerplate-3fb580276af6bc12861de42c0115c04549c98177.zip |
simplified syntax and provide a proper parser
Diffstat (limited to 'src/main/scala')
3 files changed, 96 insertions, 70 deletions
diff --git a/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala b/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala index 0d8b9c3..df50691 100644 --- a/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala +++ b/src/main/scala/cc/spray/boilerplate/BoilerplatePlugin.scala @@ -12,7 +12,7 @@ object BoilerplatePlugin extends Plugin { target in boilerplateGenerate <<= (sourceManaged in Compile), - boilerplateGenerate <<= (streams, sourceDirectory in boilerplateGenerate, target in boilerplateGenerate) map Generator.generateFromTemplates, + boilerplateGenerate <<= (streams, sourceDirectory in boilerplateGenerate, target in boilerplateGenerate) map generateFromTemplates, (sourceGenerators in Compile) <+= boilerplateGenerate, (managedSourceDirectories in Compile) <+= target in boilerplateGenerate, @@ -33,5 +33,30 @@ object BoilerplatePlugin extends Plugin { watchSources <++= (sourceDirKey, filterKey, excludeKey) map descendents def descendents(sourceDir: File, filt: FileFilter, excl: FileFilter) = sourceDir.descendantsExcept(filt, excl).get + + def generateFromTemplates(streams: TaskStreams, sourceDir: File, targetDir: File): Seq[File] = { + val files = sourceDir ** "*.template" + + def changeExtension(f: File): File = { + val (ext, name) = f.getName.reverse.span(_ != '.') + new File(f.getParent, name.drop(1).reverse.toString) + } + + val mapping = (files x rebase(sourceDir, targetDir)).map { + case (orig, target) => (orig, changeExtension(target)) + } + + mapping foreach { + case (templateFile, target) => + if (templateFile.lastModified > target.lastModified) { + streams.log.info("Generating '%s'" format target.getName) + val template = IO.read(templateFile) + IO.write(target, Generator.generateFromTemplate(template, 22)) + } else + streams.log.debug("Template '%s' older than target. Ignoring." format templateFile.getName) + } + + mapping.map(_._2) + } } } diff --git a/src/main/scala/cc/spray/boilerplate/Generator.scala b/src/main/scala/cc/spray/boilerplate/Generator.scala index d171d7b..9a9b5ab 100644 --- a/src/main/scala/cc/spray/boilerplate/Generator.scala +++ b/src/main/scala/cc/spray/boilerplate/Generator.scala @@ -1,75 +1,26 @@ package cc.spray.boilerplate -import sbt._ -import sbt.Keys._ +import util.parsing.combinator.RegexParsers object Generator { - def generateFromTemplates(streams: TaskStreams, sourceDir: File, targetDir: File): Seq[File] = { - val files = sourceDir ** "*.template" - - def changeExtension(f: File): File = { - val (ext, name) = f.getName.reverse.span(_ != '.') - new File(f.getParent, name.reverse.toString+"scala") - } - - val mapping = (files x rebase(sourceDir, targetDir)).map { - case (orig, target) => (orig, changeExtension(target)) - } - - mapping foreach { - case (templateFile, target) => - if (templateFile.lastModified > target.lastModified) { - streams.log.info("Generating '%s'" format target.getName) - val template = IO.read(templateFile) - IO.write(target, generateFromTemplate(template)) - } else - streams.log.debug("Template '%s' older than target. Ignoring." format templateFile.getName) - } - - mapping.map(_._2) - } - - val ExpandReplacement = """(?s:\*\{(.*)\}\*)""".r - def generateFromTemplate(template: String): String = - ExpandReplacement.replaceAllIn(template, { m => - val format = m.group(1) - (1 to 22).map(generate(format)).mkString - }) - - val SimpleReplacement = """\[\{(.*)\}\]""".r - val EnumerateReplacement = """\{\{([^}]*)\}([^}]+)?\}""".r - - def generate(format: String)(idx: Int): String = { - val numChars = idx.toString.length - def formatNum0(num: Int) = num.formatted("%0"+numChars+"d") - def formatNumSpace(num: Int) = num.formatted("%"+numChars+"d") - - def replaceSimple(pattern: String) = - SimpleReplacement.replaceAllIn(pattern, { m => - val pattern = m.group(1) - replaceInPattern(pattern)(idx) - }) - - def replaceExpand(pattern: String) = - EnumerateReplacement.replaceAllIn(pattern, { m => - val pattern = m.group(1) - val separator = m.group(2) match { - case null => - if (pattern.endsWith(", ") || pattern.contains("\n")) "" else ", " - case sep => sep - } - - (1 to idx).map(replaceInPattern(pattern)).mkString(separator) - }) - def replaceInPattern(pattern: String)(idx: Int): String = - // in likely identifiers replace by '04' etc. - pattern.replaceAll("(?<!\\d)1(?!\\d)", formatNum0(idx)) - .replaceAll("(?<=\\w)(?<!\\d)0(?!\\d)", formatNum0(idx - 1)) - - // in other places replace by ' 4' etc. - .replaceAll("(?<!\\w)(?<!\\d)1(?!\\d)", formatNumSpace(idx)) - .replaceAll("(?<!\\w)(?<!\\d)0(?!\\d)", formatNumSpace(idx - 1)) - - replaceExpand(replaceSimple(format)) + def generateFromTemplate(template: String, expandTo: Int): String = + generate(TemplateParser.parse(template))(expandTo) + + def formatNum0(num: Int) = num.formatted("%d") + def formatNumSpace(num: Int) = num.formatted("%d") + def replaceInPattern(pattern: String)(idx: Int): String = + // in likely identifiers replace by '04' etc. + pattern.replaceAll("(?<=\\w)(?<!\\d)(?<!##)1(?!\\d)", formatNum0(idx)) + .replaceAll("(?<=\\w)(?<!\\d)(?<!##)0(?!\\d)", formatNum0(idx - 1)) + + // in other places replace by ' 4' etc. + .replaceAll("(?<!\\w)(?<!\\d)(?<!##)1(?!\\d)", formatNumSpace(idx)) + .replaceAll("(?<!\\w)(?<!\\d)(?<!##)0(?!\\d)", formatNumSpace(idx - 1)) + + def generate(format: TemplateElement)(idx: Int): String = format match { + case Sequence(els) => els.map(e => generate(e)(idx)).mkString + case Expand(inner, sep) => (1 to idx).map(generate(inner)).mkString(sep) + case LiteralString(lit) => replaceInPattern(lit)(idx) + case FixedString(lit) => lit } } diff --git a/src/main/scala/cc/spray/boilerplate/TemplateParser.scala b/src/main/scala/cc/spray/boilerplate/TemplateParser.scala new file mode 100644 index 0000000..4e280a4 --- /dev/null +++ b/src/main/scala/cc/spray/boilerplate/TemplateParser.scala @@ -0,0 +1,50 @@ +package cc.spray.boilerplate + +import util.parsing.combinator.RegexParsers +import java.lang.RuntimeException + +sealed trait TemplateElement +case class Sequence(elements: Seq[TemplateElement]) extends TemplateElement +case class LiteralString(literal: String) extends TemplateElement +case class FixedString(literal: String) extends TemplateElement +case class Expand(inner: TemplateElement, separator: String) extends TemplateElement + +object TemplateParser extends RegexParsers { + override type Elem = Char + type Tokens = TemplateElement + override val skipWhitespace = false + + def elements: Parser[TemplateElement] = rep1(element) ^^ { + case one :: Nil => one + case several => Sequence(several) + } + + def element: Parser[TemplateElement] = literal | fixed | expand + + def literalChar: Parser[String] = """(?s:(?!\[#)(?!#[^\]]*\]).)""".r + def literalChars: Parser[String] = rep1(literalChar) ^^ { _.reduceLeft(_ + _) } + + def literal: Parser[LiteralString] = literalChars ^^ LiteralString + + def fixed: Parser[FixedString] = "##" ~> ".".r ^^ (new String(_)) ^^ FixedString + + def expand: Parser[Expand] = "[#" ~> elements ~ "#" ~ separatorChars <~ "]" ^^ { + case els ~ x ~ sep => Expand(els, sep.getOrElse(", ")) + } + + def separatorChars: Parser[Option[String]] = rep("""[^\]]""".r) ^^ (_.reduceLeftOption(_ + _)) + + def parse(input:String): TemplateElement = + phrase(elements)(new scala.util.parsing.input.CharArrayReader(input.toCharArray)) match { + case Success(res,_) => res + case x:NoSuccess => throw new RuntimeException(x.msg) + } +} + +object TestParser extends App { + def check(format: String) { + println(TemplateParser.parse(format)) + } + + check("[#abc ##1 # ++ ]") +}
\ No newline at end of file |