summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/Settings.scala
blob: 90246cead53a5e284095c9093177c1f0d9e26709 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                

                          

       
                       
 
                   
                       
 
                                       
                                    
 

                                                 




                                                 
                                
                                                    



                                       
 



                                           
                                   





                                     
                             

         









                                                 
                                                        
                              

                                                  

                                                                   

            
 
                                           
                                        
                            
                                                                                        
                                               

                                                                                
                                                                
       
               

   
                                     
                                        
                            
                                                      
                                                      


               
                               

                                                      
 
                                                                                                                                                           



                                                                                                                            




                                                                                                                                                                
                                                                                                                                     
                                                                                                                                                                   
                                                                                                                      
                                                                                                                           

                                                                                                                  






                                                                                                                                                                                 

                                                                                                          
                                                                                                                      
                                                                                               
                                                                                                    

                                                                                          
                                                                                                         
                                                                                                                                                
                                                                                                            
                                                                                                                        
                                                                              
                                                                                                      




                                                                                                                                          
                                                                                                          
                                                                                                                                                               


                                                                                               


                                                                                                                        
                                                                                          


                                                                                            


                                                                                                                          
                                                                                     

                                                                                                          
                                                                                                                                         
                                                                                                                                   




                                                                                                                             
 


                                                                                                         

                                                                                                                  
                                  

                                                                                                                              









                                                                                                                                                                
 
                               
                                                      




                                           

                                                                















                                                                                   


                                                                     



                                                                               



                                                                              
                                                               

                                                                        
                                                  

                                                            
                                 

                                                                        
                               
 




                                                             

                                                     








                                    
 
                                            




                                                                                                 
 
                                                       


                                               
                                                                   


                                                     
                     
                                     

   
                                                                    
                                                                                 
                                    
 

                                                            




                                                                 
 
                                                              


                                                                  

                                                                                     

                                   
 



                                                           

                                                                 
                                                           
                           
                                   
              



                           


                    
                                                     

                               
                                                      

   


                                                                         
             





                                                                 

                                                       
                                








                                                 

            









                                                     

                                                                               
     

                                                                                               
                                     
 
                              
                                                           
 
                                                      


                                                                 
                                                   


                                                   
                                                             
              

                        
              
         









                                                                                       


                    
                                                          

                               
                                                             
   
 


                                                                              
     

                                                                                                               





                                                                     
                    
     
                                                  
 


                                          
                                               
     










                                                                          



                                              
                            




                    




                                                                            

                                                                
             



                                                                 


                                                                 
                                                  
                          
                                
              

                                       
              
         


                    
                                               
 
                                              
                                                    





                                               

   
/* NSC -- new Scala compiler
 * Copyright 2005-2007 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$

package scala.tools.nsc

import java.io.File
import java.lang.System

class Settings(error: String => Unit) {
  def this() = this(Console.println)

  private var allsettings: List[Setting] = List()

  private def getProperty(name: String): String =
    if (System.getProperty(name) != "")
      System.getProperty(name)
    else null

  private val classpathDefault =
    if (System.getProperty("env.classpath") ne null)
      alternatePath(
        getProperty("env.classpath"),
        ".")
    else getProperty("java.class.path")

  private val bootclasspathDefault =
    alternatePath(
      concatPath(
        getProperty("sun.boot.class.path"),
        guessedScalaBootClassPath),
      "")

  private val extdirsDefault =
    alternatePath(
      concatPath(
        getProperty("java.ext.dirs"),
        guessedScalaExtDirs),
      "")

  private val pluginsDirDefault =
    if (Properties.scalaHome == null)
      ""
    else
      new File(
	new File(
	  new File(Properties.scalaHome, "misc"),
	  "scala-devel"),
	"plugins").getAbsolutePath

  private def alternatePath(p1: String, p2: => String) =
    if (p1 ne null) p1 else p2

  private def concatPath(p1: String, p2: String) =
     if ((p1 ne null) && (p2 ne null)) p1 + File.pathSeparator + p2
     else if (p1 ne null) p1
     else p2


  private def guessedScalaBootClassPath = {
    val scalaHome = Properties.scalaHome
    if (scalaHome ne null) {
      val guessJar = new File(new File(new File(scalaHome), "lib"), "scala-library.jar")
      if (guessJar.isFile()) guessJar.getPath()
      else {
        val guessDir = new File(new File(new File(scalaHome), "lib"), "library")
        if (guessDir.isDirectory()) guessDir.getPath() else null
      }
    } else null
  }

  private def guessedScalaExtDirs = {
    val scalaHome = Properties.scalaHome
    if (scalaHome ne null) {
      val guess = new File(new File(scalaHome), "lib")
      if (guess.isDirectory()) guess.getPath else null
    } else null
  }

  private val encodingDefault =
    new java.io.OutputStreamWriter(
      new java.io.ByteArrayOutputStream()).getEncoding

  val debuginfo     = new DebugSetting  ("-g", "Specify level of generated debugging info", List("none", "source", "line", "vars", "notc"), "vars", "vars")
  val nowarnings    = BooleanSetting    ("-nowarn", "Generate no warnings").hideToIDE
  val verbose       = BooleanSetting    ("-verbose", "Output messages about what the compiler is doing").hideToIDE
  val deprecation   = BooleanSetting    ("-deprecation", "Output source locations where deprecated APIs are used").hideToIDE
  val unchecked     = BooleanSetting    ("-unchecked", "Enable detailed unchecked warnings").hideToIDE
  val classpath     = new StringSetting ("-classpath", "path", "Specify where to find user class files", classpathDefault) { override val abbreviation = "-cp" }
  val sourcepath    = StringSetting     ("-sourcepath", "path", "Specify where to find input source files", "")
  val bootclasspath = StringSetting     ("-bootclasspath", "path", "Override location of bootstrap class files", bootclasspathDefault)
  val extdirs       = StringSetting     ("-extdirs", "dirs", "Override location of installed extensions", extdirsDefault)
  val outdir        = StringSetting     ("-d", "directory", "Specify where to place generated class files", ".")
  val encoding      = StringSetting     ("-encoding", "encoding", "Specify character encoding used by source files", encodingDefault)
  val target        = ChoiceSetting     ("-target", "Specify for which target object files should be built", List("jvm-1.5", "jvm-1.4", "msil", "cldc"), "jvm-1.5")
  val printLate     = BooleanSetting    ("-print", "Print program with all Scala-specific features removed").hideToIDE
  val XO            = BooleanSetting    ("-optimise", "Generates faster bytecode by applying optimisations to the program")
  val explaintypes  = BooleanSetting    ("-explaintypes", "Explain type errors in more detail").hideToIDE
  val uniqid        = BooleanSetting    ("-uniqid", "Print identifiers with unique names for debugging").hideToIDE
  val version       = BooleanSetting    ("-version", "Print product version and exit").hideToIDE
  val help          = BooleanSetting    ("-help", "Print a synopsis of standard options").hideToIDE
  val Xhelp         = BooleanSetting    ("-X", "Print a synopsis of advanced options").hideToIDE

  val assemname     = StringSetting     ("-Xassem", "file", "Name of the output assembly (only relevant with -target:msil)", "").dependsOn(target, "msil")
  val assemrefs     = StringSetting     ("-Xassem-path", "path", "List of assemblies referenced by the program (only relevant with -target:msil)", ".").dependsOn(target, "msil")
  val Xchecknull    = BooleanSetting    ("-Xcheck-null", "Emit warning on selection of nullable reference")
  val noassertions  = BooleanSetting    ("-Xdisable-assertions", "Generate no assertions and assumptions")
  val Xexperimental = BooleanSetting    ("-Xexperimental", "Enable experimental extensions")
  val XlogImplicits = BooleanSetting    ("-Xlog-implicits", "Show more info on why some implicits are not applicable")
  val Xnojline      = new BooleanSetting("-Xnojline", "Do not use JLine for editing").hideToIDE
  val nouescape     = BooleanSetting    ("-Xno-uescape", "Disables handling of \\u unicode escapes")
  val plugin        = MultiStringSetting("-Xplugin", "file", "Load a plugin from a file")
  val disable       = MultiStringSetting("-Xplugin-disable", "plugin", "Disable a plugin")
  val showPlugins   = BooleanSetting    ("-Xplugin-list", "Print a synopsis of loaded plugins").hideToIDE
  val pluginOptions = new MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") { override def helpSyntax = "-P:<plugin>:<opt>" }
  val require       = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless a plugin is available")
  val pluginsDir    = StringSetting     ("-Xpluginsdir", "path", "Location to find compiler plugins", pluginsDirDefault)
  val print         = PhasesSetting     ("-Xprint", "Print out program after")
  val Xprintpos     = BooleanSetting    ("-Xprint-pos", "Print tree positions (as offsets)").hideToIDE
  val printtypes    = BooleanSetting    ("-Xprint-types", "Print tree types (debugging option)").hideToIDE
  val prompt        = BooleanSetting    ("-Xprompt", "Display a prompt after each error (debugging option)").hideToIDE
  val resident      = BooleanSetting    ("-Xresident", "Compiler stays resident, files to compile are read from standard input").hideToIDE
  val Xshowcls      = StringSetting     ("-Xshow-class", "class", "Show class info", "")
  val Xshowobj      = StringSetting     ("-Xshow-object", "object", "Show object info", "")
  val showPhases    = BooleanSetting    ("-Xshow-phases", "Print a synopsis of compiler phases").hideToIDE
  val sourceReader  = StringSetting     ("-Xsource-reader", "classname", "Specify a custom method for reading source files", "scala.tools.nsc.io.SourceReader")

  val Yhelp         = BooleanSetting    ("-Y", "Print a synopsis of private options").hideToIDE
  val browse        = PhasesSetting     ("-Ybrowse", "Browse the abstract syntax tree after")
  val check         = PhasesSetting     ("-Ycheck", "Check the tree at start of")
  val Xcloselim     = BooleanSetting    ("-Yclosure-elim", "Perform closure elimination")
  val Xcodebase     = StringSetting     ("-Ycodebase", "codebase", "Specify the URL containing the Scala libraries", "")
  val debug         = BooleanSetting    ("-Ydebug", "Output debugging messages").hideToIDE
  val Xdce          = BooleanSetting    ("-Ydead-code", "Perform dead code elimination")
  val Xdetach       = BooleanSetting    ("-Ydetach", "Perform detaching of remote closures")
  val doc           = BooleanSetting    ("-Ydoc", "Generate documentation").hideToIDE
  val inline        = BooleanSetting    ("-Yinline", "Perform inlining when possible")
  val Xlinearizer   = ChoiceSetting     ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
  val log           = PhasesSetting     ("-Ylog", "Log operations in")
  val logAll        = BooleanSetting    ("-Ylog-all", "Log all operations").hideToIDE
  val noimports     = BooleanSetting    ("-Yno-imports", "Compile without any implicit imports")
  val nopredefs     = BooleanSetting    ("-Yno-predefs", "Compile without any implicit predefined values")
  val script        = StringSetting     ("-Xscript", "object", "Compile as a script, wrapping the code into object.main()", "").hideToIDE
  val Xshowtrees    = BooleanSetting    ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase").hideToIDE
  val skip          = PhasesSetting     ("-Yskip", "Skip")
  val Xsqueeze      = ChoiceSetting     ("-Ysqueeze", "if on, creates compact code in matching", List("on","on","off"), "on")
  val statistics    = BooleanSetting    ("-Ystatistics", "Print compiler statistics").hideToIDE
  val stop          = PhasesSetting     ("-Ystop", "Stop after phase")
  val Xwarndeadcode = BooleanSetting    ("-Ywarn-dead-code", "Emit warnings for dead code")

  val Xcasetags     = ChoiceSetting("-Ycasetags", "test integer tags for case classes", List("on","off"),
                                     /*default*/"off")

  val selfInAnnots = BooleanSetting    ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations")

  /** scaladoc specific options */
  val memberaccess   = ChoiceSetting    ("-access", "Show only public, protected/public (default) or all classes and members",
                                         List("public", "protected", "private"), "protected").dependsOn(doc)
  val pagebottom     = StringSetting    ("-bottom", "pagebottom", "Include bottom text for each page", "").dependsOn(doc)
  val doccharset     = StringSetting    ("-charset", "doccharset", "Charset for cross-platform viewing of generated documentation.", "").dependsOn(doc)
  val doctitle       = StringSetting    ("-doctitle", "doctitle", "Include title for the overview page", "Scala 2<br/>API Specification").dependsOn(doc)
  val pagefooter     = StringSetting    ("-footer", "pagefooter", "Include footer text for each page", "").dependsOn(doc)
  val pageheader     = StringSetting    ("-header", "pageheader", "Include header text for each page", "").dependsOn(doc)
  val linksource     = BooleanSetting   ("-linksource", "Generate source in HTML").hideToIDE.dependsOn(doc)
  val nocomment      = BooleanSetting   ("-nocomment", "Suppress description and tags, generate only declarations.").hideToIDE.dependsOn(doc)
  val stylesheetfile = StringSetting    ("-stylesheetfile", "stylesheetfile", "File to change style of the generated documentation", "style.css").dependsOn(doc)
  val pagetop        = StringSetting    ("-top", "pagetop", "Include top text for each page", "").dependsOn(doc)
  val windowtitle    = StringSetting    ("-windowtitle", "windowtitle", "Specify window title of generated HTML documentation", "Scala 2").dependsOn(doc)

  /** A list of all settings */
  def allSettings: List[Setting] = allsettings.reverse
  /** Disable a setting */
  def disable(s: Setting) = {
    allsettings = allsettings filter (s !=)
  }

  def checkDependencies: Boolean = {
    def hasValue(s: Setting, value: String): Boolean = s match {
      case bs: BooleanSetting => bs.value
      case ss: StringSetting  => ss.value == value
      case cs: ChoiceSetting  => cs.value == value
      case _ => "" == value
    }
    var ok = true
    for (setting <- allsettings if !setting.dependency.isEmpty) {
      val (dep, value) = setting.dependency.get
      if (! (setting.isDefault || hasValue(dep, value))) {
        error("incomplete option " + setting.name + " (requires " + dep.name + ")")
        ok = false
      }
    }
    ok
  }

  /** A base class for settings of all types.
   *  Subclasses each define a `value' field of the appropriate type.
   */
  abstract class Setting(descr: String) {

    /** The name of the option as written on the command line, '-' included. */
    def name: String

    /** If first arg defines this setting, consume it as well as all following
     *  args needed to define the setting. If this can be done without
     *  error, set value field and return suffix of args else
     *  issue error message and return the arguments unchanged.
     *  If first arg does not define this setting return args unchanged.
     */
    def tryToSet(args: List[String]): List[String]

    /** The syntax defining this setting in a help string */
    def helpSyntax: String = name

    /** A description of the purpose of this setting in a help string */
    def helpDescription = descr

    /** Return a list of strings that can be used to recreate
      * the receiver's current setting.
      */
    def unparse: List[String]

    /** override if option should be hidden from IDE.
      */
    var hiddenToIDE: Boolean = false
    def hideToIDE: this.type = {
      hiddenToIDE = true
      this
    }
    def showToIDE: this.type = {
      hiddenToIDE = false
      this
    }

    protected var setByUser: Boolean = false
    def isDefault: Boolean = !setByUser

    protected[Settings] var dependency: Option[(Setting, String)] = None
    def dependsOn(s: Setting, value: String): this.type = { dependency = Some((s, value)); this }
    def dependsOn(s: Setting): this.type = dependsOn(s, "")

    def isStandard: Boolean = !isAdvanced && !isPrivate
    def isAdvanced: Boolean =
      (name startsWith "-X") && !(name eq "-X")
    def isPrivate: Boolean =
      (name == "-P") || ((name startsWith "-Y") && !(name eq "-Y"))
    def isDocOption: Boolean =
      !dependency.isEmpty && dependency.get._1 == doc

    // initialization
    allsettings = this :: allsettings
  }

  /** A setting represented by a boolean flag (false, unless set) */
  case class BooleanSetting(name: String, descr: String) extends Setting(descr) {
    protected var v: Boolean = false

    def value: Boolean = this.v
    def value_=(s: Boolean) { setByUser = true; this.v = s }

    def tryToSet(args: List[String]): List[String] = args match {
      case n :: rest if (n == name) => value = true; rest
      case _ => args
    }

    def unparse: List[String] = if (value) List(name) else Nil
  }

  /** A setting represented by a string, (`default' unless set) */
  case class StringSetting(name: String, arg: String, descr: String, default: String)
  extends Setting(descr) {
    hideToIDE
    def abbreviation: String = null

    protected var v: String = default

    def value: String = this.v
    def value_=(s: String) { setByUser = true; this.v = s }

    def tryToSet(args: List[String]): List[String] = args match {
      case n :: rest if (name == n || abbreviation == n) =>
        if (rest.isEmpty) {
          error("missing argument")
          args
        } else {
          value = rest.head
          rest.tail
        }
      case _ => args
    }

    override def helpSyntax = name + " <" + arg + ">"

    def unparse: List[String] =
      if (value == default) Nil else List(name, value)
  }

  /** A setting that accumulates all strings supplied to it */
  case class MultiStringSetting(name: String, arg: String, descr: String)
  extends Setting(descr) {
    hideToIDE
    protected var v: List[String] = Nil
    def value = v
    def appendToValue(str: String) { v = v ::: List(str) }

    protected val nameColon = name + ":"
    def tryToSet(args: List[String]): List[String] = args match {
      case arg :: rest if (arg startsWith nameColon) =>
        val toadd = arg.substring(nameColon.length())
        if (toadd.length == 0) {
          error("empty argument to " + nameColon)
          args
        } else {
          appendToValue(toadd)
          rest
        }

      case opt :: arg :: rest if (opt == name) =>
        appendToValue(arg)
        rest

      case _ => args
    }

    override def helpSyntax = name + ":<" + arg + ">"

    def unparse: List[String] =
      for (opt <- value)
	yield nameColon+opt
  }

  /** A setting represented by a string in a given set of <code>choices</code>,
   *  (<code>default</code> unless set).
   */
  case class ChoiceSetting(name: String, descr: String, choices: List[String], default: String)
  extends Setting(descr + choices.mkString(" (", ",", ")")) {
    protected var v: String = default

    def value: String = this.v
    def value_=(s: String) { setByUser = true; this.v = s }

    protected def argument: String = name.substring(1)

    def tryToSet(args: List[String]): List[String] = args match {
      case n :: rest if (n startsWith (name + ":")) =>
        val choice = n.substring(name.length() + 1)
        if (!(choices contains choice)) {
          error(
            if (choice == "") "missing " + argument
            else "unknown " + argument + " '" + choice + "'")
          args
        } else {
          value = choice
          rest
        }
      case n :: choice :: rest if n == name => // alternative to be consistent with IDE
        if (!(choices contains choice)) {
          error(
            if (choice == "") "missing " + argument
            else "unknown " + argument + " '" + choice + "'")
          args
        } else {
          value = choice
          rest
        }
      case _ => args
    }

    override def helpSyntax = name + ":<" + argument + ">"

    def unparse: List[String] =
      if (value == default) Nil else List(name + ":" + value)
  }

  /** Same as ChoiceSetting but have a <code>level</code> int which tells the
   *  index of the selected choice. The <code>defaultEmpty</code> is used when
   *  this setting is used without specifying any of the available choices.
   */
  class DebugSetting(name: String, descr: String, choices: List[String], default: String, defaultEmpty: String)
  extends ChoiceSetting(name, descr, choices, default) {

    def indexOf[a](xs: List[a], e: a): Option[Int] = xs match {
      case y :: ys => if (e == y) Some(0) else indexOf(ys, e) match {
          case Some(idx) => Some(1 + idx)
          case None => None
        }
      case _ => None
    }
    var level: Int = indexOf(choices, default).get

    override def value_=(choice: String) {
      setByUser = true
      this.v = choice
      this.level = indexOf(choices, choice).get
    }

    override def tryToSet(args: List[String]): List[String] = args match {
      case n :: rest if (n startsWith (name + ":")) =>
        val choice = n.substring(name.length() + 1)
        if (!(choices contains choice)) {
          error(
              if (choice == "") "missing " + argument
              else "unknown " + argument + " '" + choice + "'")
          args
        } else {
          value = choice
          rest
        }

      case n :: rest if (n startsWith name) =>
        value = defaultEmpty
        rest

      case _ => args
    }
  }

  /** A setting represented by a list of strings which should be prefixes of
   *  phase names. This is not checked here, however.
   *  (the empty list, unless set)
   */
  case class PhasesSetting(name: String, descr: String)
  extends Setting(descr + " <phase>") { // (see -showphases)") {
    hideToIDE
    protected var v: List[String] = List()

    def value: List[String] = this.v
    def value_=(s: List[String]) { setByUser = true; this.v = s }

    def tryToSet(args: List[String]): List[String] = args match {
      case n :: rest if (n startsWith (name + ":")) =>
        val phase = n.substring(name.length() + 1)
        if (phase == "") {
          error("missing phase")
          args
        } else {
          value = value ::: List(phase)
          rest
        }
      case _ => args
    }

    override def helpSyntax = name + ":<phase>"

    def contains(phasename: String): Boolean =
      value exists (str => phasename startsWith str)

    def unparse: List[String] =
      (value.foldLeft[List[String]]
          (Nil)
          ((args, phase) =>
            List(name + ":" + phase) ::: args))
  }
}