/* Copyright 2009-2015 EPFL, Lausanne */ package leon import OptionParsers._ import purescala.Definitions._ import purescala.DefOps.fullName abstract class LeonOptionDef[+A] { val name: String val description: String val default: A val parser: OptionParser[A] val usageRhs: String def usageDesc = { if (usageRhs.isEmpty) s"--$name" else s"--$name=$usageRhs" } def helpString = { f"$usageDesc%-26s" + description.replaceAll("\n", "\n" + " " * 26) } private def parseValue(s: String)(implicit reporter: Reporter): A = { try { parser(s) } catch { case _ : IllegalArgumentException => reporter.error(s"Invalid option usage: $usageDesc") Main.displayHelp(reporter, error = true) } } def parse(s: String)(implicit reporter: Reporter): LeonOption[A] = LeonOption(this)(parseValue(s)) def withDefaultValue: LeonOption[A] = LeonOption(this)(default) // @mk: FIXME: Is this cool? override def equals(other: Any) = other match { case that: LeonOptionDef[_] => this.name == that.name case _ => false } override def hashCode = name.hashCode } case class LeonFlagOptionDef(name: String, description: String, default: Boolean) extends LeonOptionDef[Boolean] { val parser = booleanParser val usageRhs = "" } case class LeonStringOptionDef(name: String, description: String, default: String, usageRhs: String) extends LeonOptionDef[String] { val parser = stringParser } case class LeonLongOptionDef(name: String, description: String, default: Long, usageRhs: String) extends LeonOptionDef[Long] { val parser = longParser } class LeonOption[+A] private (val optionDef: LeonOptionDef[A], val value: A) { override def toString = s"--${optionDef.name}=$value" override def equals(other: Any) = other match { case LeonOption(optionDef, value) => optionDef.name == this.optionDef.name && value == this.value case _ => false } override def hashCode = optionDef.hashCode } object LeonOption { def apply[A](optionDef: LeonOptionDef[A])(value: A) = { new LeonOption(optionDef, value) } def unapply[A](opt: LeonOption[A]) = Some((opt.optionDef, opt.value)) } object OptionParsers { type OptionParser[A] = String => A val longParser: OptionParser[Long] = _.toLong val stringParser: OptionParser[String] = x => x def booleanParser: OptionParser[Boolean] = { case "on" | "true" | "yes" | "" => true case "off" | "false" | "no" => false case _ => throw new IllegalArgumentException } def seqParser[A](base: OptionParser[A]): OptionParser[Seq[A]] = s => { s.split(",").filter(_.nonEmpty).map(base) } def setParser[A](base: OptionParser[A]): OptionParser[Set[A]] = s => { s.split(",").filter(_.nonEmpty).map(base).toSet } } object OptionsHelpers { private val matcher = s"--(.*)=(.*)".r private val matcherWithout = s"--(.*)".r def nameValue(s: String) = s match { case matcher(name, value) => (name, value) case matcherWithout(name) => (name, "") case _ => throw new IllegalArgumentException } // helper for options that include patterns def matcher(patterns: Traversable[String]): String => Boolean = { val regexPatterns = patterns map { s => import java.util.regex.Pattern // wildcards become ".*", rest is quoted. var p = s.split("_").toList.map(Pattern.quote).mkString(".*") // We account for _ at begining and end if (s.endsWith("_")) { p += ".*" } if (s.startsWith("_")) { p = ".*"+p } // Finally, we match qualified suffixes (e.g. searching for 'size' will // match 'List.size' but not 'thesize') Pattern.compile("(.+\\.)?"+p) } { (name: String) => regexPatterns.exists(p => p.matcher(name).matches()) } } def fdMatcher(pgm: Program)(patterns: Traversable[String]): FunDef => Boolean = { { (fd: FunDef) => fullName(fd)(pgm) } andThen matcher(patterns) } def filterInclusive[T](included: Option[T => Boolean], excluded: Option[T => Boolean]): T => Boolean = { included match { case Some(i) => i case None => excluded match { case Some(f) => { (t: T) => !f(t) } case None => { (t: T) => true } } } } }