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


       
                               
 

                   


                                                     

                                                                                  
   

                               




                                                               

                                                     
                                                                              

                            













                                                                             
 




                                                        








                                                              
                                                                            
































                                                                       
                          
                   
                                                 




































                                                                           
                                      



                                                      




                                                                          
 
                                                  
 




                                                          



                                                      
                                                              






                                                            
/* NSC -- new Scala compiler
 * Copyright 2007-2009 LAMP/EPFL
 * @author Lex Spoon
 * Updated by Anders Bach Nielsen
 */
// $Id$

package scala.tools.nsc.plugins

import java.io.File

/** Support for run-time loading of compiler plugins.
 *
 *  @author Lex Spoon
 *  @version 1.1, 2009/1/2
 *  Updated 2009/1/2 by Anders Bach Nielsen: Added features to implement SIP 00002
 */
trait Plugins { self: Global =>

  /** Load a rough list of the plugins.  For speed, it
   *  does not instantiate a compiler run.  Therefore it cannot
   *  test for same-named phases or other problems that are
   *  filtered from the final list of plugins. */
  protected def loadRoughPluginsList(): List[Plugin] = {
    val jars = settings.plugin.value.map(new File(_))
    val dirs =
      for (name <- settings.pluginsDir.value.split(File.pathSeparator).toList)
	yield new File(name)

    for (plugClass <- Plugin.loadAllFrom(jars, dirs, settings.disable.value))
    yield Plugin.instantiate(plugClass, this)
  }

  private var roughPluginsListCache: Option[List[Plugin]] = None

  protected def roughPluginsList: List[Plugin] =
    roughPluginsListCache match {
      case Some(list) => list
      case None =>
	roughPluginsListCache = Some(loadRoughPluginsList)
        roughPluginsListCache.get
    }


  /** Load all available plugins.  Skips plugins that
   *  either have the same name as another one, or which
   *  define a phase name that another one does.
   */
  protected def loadPlugins(): List[Plugin] = {
    // remove any with conflicting names or subcomponent names
    def pick(
      plugins: List[Plugin],
      plugNames: Set[String],
      phaseNames: Set[String]): List[Plugin] =
    {
      plugins match {
	case Nil => Nil
	case plug :: rest =>
	  val plugPhaseNames = Set.empty ++ plug.components.map(_.phaseName)
	  def withoutPlug = pick(rest, plugNames, plugPhaseNames)
	  def withPlug =
	    (plug ::
	     pick(rest,
		  plugNames+plug.name,
		  phaseNames++plugPhaseNames))

	  if (plugNames.contains(plug.name)) {
	    if (settings.verbose.value)
	      inform("[skipping a repeated plugin: " + plug.name + "]")
	    withoutPlug
	  } else if (settings.disable.value contains(plug.name)) {
	    if (settings.verbose.value)
	      inform("[disabling plugin: " + plug.name + "]")
	    withoutPlug
	  } else {
	    val commonPhases = phaseNames.intersect(plugPhaseNames)
	    if (!commonPhases.isEmpty) {
	      if (settings.verbose.value)
		inform("[skipping plugin " + plug.name +
		       "because it repeats phase names: " +
		       commonPhases.mkString(", ") + "]")
	      withoutPlug
	    } else {
	      if (settings.verbose.value)
		inform("[loaded plugin " + plug.name + "]")
	      withPlug
	    }
	  }
      }
    }

    val plugs =
    pick(roughPluginsList,
	 Set.empty,
	 Set.empty ++ phasesSet.map(_.phaseName))

    for (req <- settings.require.value; if !plugs.exists(p => p.name==req))
      error("Missing required plugin: " + req)


    for (plug <- plugs) {
      val nameColon = plug.name + ":"
      val opts = for {
	raw <- settings.pluginOptions.value
	if raw.startsWith(nameColon)
      } yield raw.substring(nameColon.length)

      if (!opts.isEmpty)
	plug.processOptions(opts, error)
    }

    for {
      opt <- settings.pluginOptions.value
      if !plugs.exists(p => opt.startsWith(p.name + ":"))
    } error("bad option: -P:" + opt)

    plugs
  }


  private var pluginsCache: Option[List[Plugin]] = None

  def plugins: List[Plugin] = {
    if (pluginsCache.isEmpty)
      pluginsCache = Some(loadPlugins)
    pluginsCache.get
  }


  /** A description of all the plugins that are loaded */
  def pluginDescriptions: String = {
    val messages =
      for (plugin <- roughPluginsList)
	yield plugin.name + " - " + plugin.description
    messages.mkString("\n")
  }

  /**
   * Extract all phases supplied by plugins and add them to the phasesSet.
   * @see phasesSet
   */
  protected def computePluginPhases() {

    var plugPhases = plugins.flatMap(_.components)

    // Add all phases supplied by plugins to the phasesSet
    for (pPhase <- plugPhases) {
      phasesSet += pPhase
     }
   }

  /** Summary of the options for all loaded plugins */
  def pluginOptionsHelp: String = {
    val buf = new StringBuffer
    for (plug <- roughPluginsList; help <- plug.optionsHelp) {
      buf append ("Options for plugin " + plug.name + ":\n")
      buf append help
      buf append "\n"
    }
    buf.toString
  }
}