From 965d5f0dde734db5dacf354676bb7422522f87de Mon Sep 17 00:00:00 2001
From: Manos Koukoutos <emmanouil.koukoutos@epfl.ch>
Date: Tue, 15 Mar 2016 13:29:53 +0100
Subject: [PATCH] LeonOptions should use Option

---
 src/main/scala/leon/GlobalOptions.scala       | 15 ++---
 src/main/scala/leon/LeonOption.scala          | 63 ++++++++++---------
 src/main/scala/leon/Main.scala                | 19 +++---
 .../scala/leon/laziness/LazinessUtil.scala    |  9 +--
 .../scala/leon/utils/FileOutputPhase.scala    |  8 +--
 5 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/src/main/scala/leon/GlobalOptions.scala b/src/main/scala/leon/GlobalOptions.scala
index 63648ca33..9632926a6 100644
--- a/src/main/scala/leon/GlobalOptions.scala
+++ b/src/main/scala/leon/GlobalOptions.scala
@@ -51,19 +51,16 @@ object GlobalOptions extends LeonComponent {
     }
     val default = Set[DebugSection]()
     val usageRhs = "d1,d2,..."
-    val debugParser: OptionParser[Set[DebugSection]] = s => {
+    private val debugParser: OptionParser[Set[DebugSection]] = s => {
       if (s == "all") {
-        DebugSections.all
+        Some(DebugSections.all)
       } else {
-        DebugSections.all.find(_.name == s) match {
-          case Some(rs) =>
-            Set(rs)
-          case None =>
-            throw new IllegalArgumentException
-        }
+        DebugSections.all.find(_.name == s).map(Set(_))
       }
     }
-    val parser: String => Set[DebugSection] = setParser[Set[DebugSection]](debugParser)(_).flatten
+    val parser: String => Option[Set[DebugSection]] = {
+      setParser[Set[DebugSection]](debugParser)(_).map(_.flatten)
+    }
   }
 
   val optTimeout = LeonLongOptionDef(
diff --git a/src/main/scala/leon/LeonOption.scala b/src/main/scala/leon/LeonOption.scala
index 642092d0f..d1f93981f 100644
--- a/src/main/scala/leon/LeonOption.scala
+++ b/src/main/scala/leon/LeonOption.scala
@@ -7,6 +7,8 @@ import OptionParsers._
 import purescala.Definitions._
 import purescala.DefOps.fullName
 
+import scala.util.Try
+
 abstract class LeonOptionDef[+A] {
   val name: String
   val description: String
@@ -22,14 +24,12 @@ abstract class LeonOptionDef[+A] {
   }
 
   private def parseValue(s: String)(implicit reporter: Reporter): A = {
-    try { parser(s) }
-    catch {
-      case _ : IllegalArgumentException =>
-        reporter.fatalError(
-          s"Invalid option usage: --$name\n" +
-          "Try 'leon --help' for more information."
-        )
-    }
+    parser(s).getOrElse(
+      reporter.fatalError(
+        s"Invalid option usage: --$name\n" +
+        "Try 'leon --help' for more information."
+      )
+    )
   }
 
   def parse(s: String)(implicit reporter: Reporter): LeonOption[A] =
@@ -67,7 +67,7 @@ class LeonOption[+A] private (val optionDef: LeonOptionDef[A], val value: A) {
       optionDef.name == this.optionDef.name && value == this.value
     case _ => false
   }
-  override def hashCode = optionDef.hashCode
+  override def hashCode = optionDef.hashCode + value.hashCode
 }
 
 object LeonOption {
@@ -78,20 +78,28 @@ object LeonOption {
 }
 
 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
+  type OptionParser[A] = String => Option[A]
+
+  val longParser: OptionParser[Long] = { s =>
+    Try(s.toLong).toOption
   }
+  val stringParser: OptionParser[String] = Some(_)
+  val booleanParser: OptionParser[Boolean] = {
+    case "on"  | "true"  | "yes" | "" => Some(true)
+    case "off" | "false" | "no"       => Some(false)
+    case _  => None
+  }
+
   def seqParser[A](base: OptionParser[A]): OptionParser[Seq[A]] = s => {
-    s.split(",").filter(_.nonEmpty).map(base)
+    @inline def foo: Option[Seq[A]] = Some(
+      s.split(",")
+        .filter(_.nonEmpty)
+        .map(base andThen (_.getOrElse(return None)))
+    )
+    foo
   }
-  def setParser[A](base: OptionParser[A]): OptionParser[Set[A]] = s => {
-    s.split(",").filter(_.nonEmpty).map(base).toSet
+  def setParser[A](base: OptionParser[A]): OptionParser[Set[A]] = {
+    seqParser(base)(_).map(_.toSet)
   }
 
 }
@@ -103,9 +111,9 @@ object OptionsHelpers {
   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
+    case matcher(name, value) => Some(name, value)
+    case matcherWithout(name) => Some(name, "")
+    case _ => None
   }
 
   // helper for options that include patterns
@@ -131,7 +139,7 @@ object OptionsHelpers {
       Pattern.compile("(.+\\.)?"+p)
     }
 
-    { (name: String) => regexPatterns.exists(p => p.matcher(name).matches()) }
+    (name: String) => regexPatterns.exists(p => p.matcher(name).matches())
   }
 
   def fdMatcher(pgm: Program)(patterns: Traversable[String]): FunDef => Boolean = {
@@ -144,11 +152,8 @@ object OptionsHelpers {
         i
       case None =>
         excluded match {
-          case Some(f) =>
-            { (t: T) => !f(t) }
-
-          case None =>
-            { (t: T) => true }
+          case Some(f) => (t: T) => !f(t)
+          case None    => (t: T) => true
         }
     }
   }
diff --git a/src/main/scala/leon/Main.scala b/src/main/scala/leon/Main.scala
index c429165e8..02a21c508 100644
--- a/src/main/scala/leon/Main.scala
+++ b/src/main/scala/leon/Main.scala
@@ -57,7 +57,7 @@ object Main {
     val optHelp        = LeonFlagOptionDef("help",        "Show help message",                                         false)
     val optInstrument  = LeonFlagOptionDef("instrument",  "Instrument the code for inferring time/depth/stack bounds", false)
     val optInferInv    = LeonFlagOptionDef("inferInv",    "Infer invariants from (instrumented) the code",             false)
-    val optLazyEval = LeonFlagOptionDef("lazy", "Handles programs that may use the lazy construct", false)
+    val optLazyEval    = LeonFlagOptionDef("lazy",        "Handles programs that may use the 'lazy' construct",        false)
     val optGenc        = LeonFlagOptionDef("genc",        "Generate C code",                                           false)
 
     override val definedOptions: Set[LeonOptionDef[Any]] =
@@ -109,15 +109,13 @@ object Main {
     val files = args.filterNot(_.startsWith("-")).map(new java.io.File(_))
 
     val leonOptions: Seq[LeonOption[Any]] = options.map { opt =>
-      val (name, value) = try {
-        OptionsHelpers.nameValue(opt)
-      } catch {
-        case _: IllegalArgumentException =>
-          initReporter.fatalError(
-            s"Malformed option $opt. Options should have the form --name or --name=value")
-      }
+      val (name, value) = OptionsHelpers.nameValue(opt).getOrElse(
+        initReporter.fatalError(
+          s"Malformed option $opt. Options should have the form --name or --name=value"
+        )
+      )
       // Find respective LeonOptionDef, or report an unknown option
-      val df = allOptions.find(_. name == name).getOrElse{
+      val df = allOptions.find(_.name == name).getOrElse{
         initReporter.fatalError(
           s"Unknown option: $name\n" +
           "Try 'leon --help' for more information."
@@ -128,7 +126,8 @@ object Main {
 
     val reporter = new DefaultReporter(
       leonOptions.collectFirst {
-        case LeonOption(GlobalOptions.optDebug, sections) => sections.asInstanceOf[Set[DebugSection]]
+        case LeonOption(GlobalOptions.optDebug, sections) =>
+          sections.asInstanceOf[Set[DebugSection]]
       }.getOrElse(Set[DebugSection]())
     )
 
diff --git a/src/main/scala/leon/laziness/LazinessUtil.scala b/src/main/scala/leon/laziness/LazinessUtil.scala
index f65c385ed..0a9f97035 100644
--- a/src/main/scala/leon/laziness/LazinessUtil.scala
+++ b/src/main/scala/leon/laziness/LazinessUtil.scala
@@ -11,6 +11,7 @@ import java.io.File
 import java.io.FileWriter
 import java.io.BufferedWriter
 import scala.util.matching.Regex
+import utils.FileOutputPhase
 
 object LazinessUtil {
 
@@ -19,13 +20,7 @@ object LazinessUtil {
   }
 
   def prettyPrintProgramToFile(p: Program, ctx: LeonContext, suffix: String, uniqueIds: Boolean = false) {
-    val optOutputDirectory = new LeonOptionDef[String] {
-      val name = "o"
-      val description = "Output directory"
-      val default = "leon.out"
-      val usageRhs = "dir"
-      val parser = (x: String) => x
-    }
+    val optOutputDirectory = FileOutputPhase.optOutputDirectory
     val outputFolder = ctx.findOptionOrDefault(optOutputDirectory)
     try {
       new File(outputFolder).mkdir()
diff --git a/src/main/scala/leon/utils/FileOutputPhase.scala b/src/main/scala/leon/utils/FileOutputPhase.scala
index 6f2fc3753..140a863ac 100644
--- a/src/main/scala/leon/utils/FileOutputPhase.scala
+++ b/src/main/scala/leon/utils/FileOutputPhase.scala
@@ -11,13 +11,7 @@ object FileOutputPhase extends UnitPhase[Program] {
   val name = "File output"
   val description = "Output parsed/generated program to the specified directory (default: leon.out)"
 
-  val optOutputDirectory = new LeonOptionDef[String] {
-    val name = "o"
-    val description = "Output directory"
-    val default = "leon.out"
-    val usageRhs = "dir"
-    val parser = (x: String) => x
-  }
+  val optOutputDirectory = LeonStringOptionDef("o", "Output directory", "leon.out", "dir")
 
   override val definedOptions: Set[LeonOptionDef[Any]] = Set(optOutputDirectory)
 
-- 
GitLab