diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2008-05-23 16:16:17 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2008-05-23 16:16:17 +0000 |
commit | 4cba60178d2f49f14b23039e47ac90612deb9046 (patch) | |
tree | 1f083706cda428a44c0b5b23fc034139732dcb34 | |
parent | b1cf78869fcb70db18af04d9626d26b95876f652 (diff) | |
download | scala-4cba60178d2f49f14b23039e47ac90612deb9046.tar.gz scala-4cba60178d2f49f14b23039e47ac90612deb9046.tar.bz2 scala-4cba60178d2f49f14b23039e47ac90612deb9046.zip |
Added Scala compiler plugin Template.
16 files changed, 596 insertions, 0 deletions
diff --git a/docs/examples/plugintemplate/.classpath b/docs/examples/plugintemplate/.classpath new file mode 100644 index 0000000000..e9069639ae --- /dev/null +++ b/docs/examples/plugintemplate/.classpath @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="doc/examples"/> + <classpathentry kind="src" path="test"/> + <classpathentry kind="con" path="ch.epfl.lamp.sdt.launching.SCALA_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="lib" path="/Applications/eclipse-3.4M6a/plugins/ch.epfl.lamp.sdt.core_2.7.1.r14724-b20080421111118/lib/scala-compiler.jar"/> + <classpathentry kind="lib" path="lib/scalatest.jar"/> + <classpathentry kind="output" path="build/eclipse"/> +</classpath> diff --git a/docs/examples/plugintemplate/.project b/docs/examples/plugintemplate/.project new file mode 100644 index 0000000000..075b0c580c --- /dev/null +++ b/docs/examples/plugintemplate/.project @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>plugintemplate</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>ch.epfl.lamp.sdt.core.scalabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>ch.epfl.lamp.sdt.core.scalanature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/docs/examples/plugintemplate/.settings/de.loskutov.anyedit.AnyEditTools.prefs b/docs/examples/plugintemplate/.settings/de.loskutov.anyedit.AnyEditTools.prefs new file mode 100644 index 0000000000..2031891e97 --- /dev/null +++ b/docs/examples/plugintemplate/.settings/de.loskutov.anyedit.AnyEditTools.prefs @@ -0,0 +1,15 @@ +#Fri May 23 08:03:52 CEST 2008 +activeContentFilterList=*.makefile,makefile,*.Makefile,Makefile,Makefile.*,*.mk,MANIFEST.MF +convertActionOnSaave=AnyEdit.CnvrtTabToSpaces +eclipse.preferences.version=1 +inActiveContentFilterList= +javaTabWidthForJava=true +org.eclipse.jdt.ui.editor.tab.width=2 +projectPropsEnabled=false +removeTrailingSpaces=true +replaceAllSpaces=false +replaceAllTabs=false +saveAndAddLine=false +saveAndConvert=false +saveAndTrim=true +useModulo4Tabs=false diff --git a/docs/examples/plugintemplate/build.xml b/docs/examples/plugintemplate/build.xml new file mode 100644 index 0000000000..0ea47b4da8 --- /dev/null +++ b/docs/examples/plugintemplate/build.xml @@ -0,0 +1,265 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<project name="plugintemplate" default="build"> + <!-- Edit the file plugin.properties to set + - scala.home + - plugin.name + - plugin.commandname + - plugin.description + - plugin.mainclass + - version numbers + --> + <property file="${basedir}/plugin.properties"/> + + <property name="version" value="${version.major}.${version.minor}"/> + + <taskdef resource="scala/tools/ant/antlib.xml"> + <classpath> + <pathelement location="${scala.home}/lib/scala-compiler.jar"/> + <pathelement location="${scala.home}/lib/scala-library.jar"/> + </classpath> + </taskdef> + + + <!-- ================================================================= + End-user targets + ================================================================== --> + + <target name="build" depends="build.main"/> + <target name="build.all" depends="build.done"/> + <target name="test" depends="test.all"/> + <target name="guitest" depends="guitest.all"/> + <target name="doc" depends="doc.done"/> + <target name="pack" depends="pack.done"/> + <target name="dist" depends="dist.done"/> + <target name="clean" depends="clean.all"/> + + <!-- ================================================================= + Build targets + ================================================================== --> + + <target name="build.main"> + <mkdir dir="build/build.main"/> + <scalac srcdir="src" + destdir="build/build.main" + includes="**/*.scala"> + <classpath> + <pathelement location="${scala.home}/lib/scala-library.jar"/> + <pathelement location="${scala.home}/lib/scala-compiler.jar"/> + </classpath> + </scalac> + </target> + + <target name="build.test" depends="build.main"> + <mkdir dir="build/build.test"/> + <scalac srcdir="test" + destdir="build/build.test" + includes="**/*.scala"> + <classpath> + <pathelement location="${scala.home}/lib/scala-library.jar"/> + <pathelement location="${scala.home}/lib/scala-compiler.jar"/> + <pathelement location="lib/scalatest.jar"/> + <pathelement location="build/build.main"/> + </classpath> + </scalac> + </target> + + <target name="build.examples" depends="build.test"> + <mkdir dir="build/build.examples"/> + <scalac srcdir="doc/examples" + destdir="build/build.examples" + includes="**/*.scala"> + <classpath> + <pathelement location="${scala.home}/lib/scala-library.jar"/> + <pathelement location="${scala.home}/lib/scala-compiler.jar"/> + <pathelement location="build/build.main"/> + </classpath> + </scalac> + </target> + + <target name="build.done" depends="build.examples"/> + + <!-- ================================================================= + Test targets + ================================================================== --> + + <target name="test.all" depends="build.done"> + <!-- fork="true" is good for running the graphical mode --> + <java classname="org.scalatest.tools.Runner" fork="true"> + <classpath> + <pathelement location="${scala.home}/lib/scala-compiler.jar" /> + <pathelement location="${scala.home}/lib/scala-library.jar" /> + <pathelement location="lib/scalatest.jar" /> + <pathelement location="build/build.main" /> + <pathelement location="build/build.test" /> + </classpath> + + <arg value="-p" /> + <arg value="build/build.test" /> + + <arg value="-o" /> + </java> + </target> + + <target name="guitest.all" depends="build.done"> + <!-- fork="true" is good for running the graphical mode --> + <java classname="org.scalatest.tools.Runner" fork="true"> + <classpath> + <pathelement location="${scala.home}/lib/scala-compiler.jar" /> + <pathelement location="${scala.home}/lib/scala-library.jar" /> + <pathelement location="lib/scalatest.jar" /> + <pathelement location="build/build.main" /> + <pathelement location="build/build.test" /> + </classpath> + + <arg value="-p" /> + <arg value="build/build.test" /> + + <arg value="-g" /> + </java> + </target> + + <!-- ================================================================= + Doc targets + ================================================================== --> + + <target name="doc.main"> + <mkdir dir="doc/api"/> + <scaladoc srcdir="src" + destdir="doc/api" + includes="**/*.scala"> + <classpath> + <pathelement location="${scala.home}/lib/scala-library.jar"/> + <pathelement location="${scala.home}/lib/scala-compiler.jar"/> + </classpath> + </scaladoc> + </target> + + <target name="doc.done" depends="doc.main"/> + + <!-- ================================================================= + Pack targets + ================================================================== --> + + <target name="pack.main" depends="build.done"> + <mkdir dir="build/pack"/> + <jar destfile="build/pack/${plugin.name}.jar"> + <fileset dir="build/build.main"/> + <fileset file="plugin.properties"/> + <fileset file="misc/scalac-plugin.xml"/> + </jar> + </target> + + <target name="pack.src" depends="pack.main"> + <jar destfile="build/pack/${plugin.name}-src.jar" + basedir="src" + includes="**/*.scala"/> + </target> + + <target name="pack.done" depends="pack.src"/> + + <!-- ================================================================= + Dist targets + ================================================================== --> + + <target name="dist.bin" depends="test.all,pack.done,doc.done"> + <mkdir dir="build/toolscript"/> + <scalascript + file="build/toolscript/${plugin.commandname}" + class="${plugin.mainclass}"/> + <chmod dir="build/toolscript" perm="a+rx" excludes="*.bat"/> + </target> + + <target name="dist.archive" depends="dist.bin"> + <mkdir dir="build/dist"/> + <tar destfile="build/dist/${plugin.name}-${version}.tgz" + compression="gzip"> + <tarfileset prefix="lib" dir="build/pack" + includes="${plugin.name}.jar"/> + <tarfileset prefix="src" dir="build/pack" + includes="${plugin.name}-src.jar"/> + <tarfileset prefix="doc/${plugin.name}" dir="doc" + includes="README"/> + <tarfileset prefix="doc/${plugin.name}" dir="doc" + includes="examples/**"/> + <tarfileset prefix="doc/${plugin.name}" dir="doc" + includes="api/**"/> + <tarfileset prefix="bin" dir="build/toolscript" + includes="${plugin.commandname}" mode="755"/> + <tarfileset prefix="bin" dir="build/toolscript" + includes="${plugin.commandname}.bat"/> + <tarfileset prefix="misc/scala-devel/plugins" dir="build/pack" + includes="${plugin.name}.jar"/> + </tar> + </target> + + <target name="dist.sbaz" depends="dist.archive"> + <sbaz file="build/dist/${plugin.name}-${version}.sbp" + adfile="build/dist/${plugin.name}-${version}.advert" + name="${plugin.name}" + version="${version}" + depends="scala-devel" + desc="${plugin.description}" + link="${plugin.sbazbaseurl}/${plugin.name}-${version}.sbp"> + <libset dir="build/pack" includes="${plugin.name}.jar"/> + <srcset dir="build/pack" includes="${plugin.name}-src.jar"/> + <docset dir="doc" includes="README"/> + <docset dir="doc" includes="examples/**"/> + <docset dir="doc" includes="api/**"/> + <binset dir="build/toolscript"/> + <looseset destination="misc/scala-devel/plugins"> + <fileset file="build/pack/${plugin.name}.jar"/> + </looseset> + </sbaz> + </target> + + <target name="dist.done" depends="dist.sbaz"/> + + <!-- ================================================================= + Local installation + ================================================================== --> + + <target name="install" depends="dist.done"> + <exec executable="sbaz"> + <arg line="-v install -f build/dist/${plugin.name}-${version}.sbp"/> + </exec> + </target> + + <target name="uninstall"> + <exec executable="sbaz"> + <arg line="remove ${plugin.name}"/> + </exec> + </target> + + <!-- ================================================================= + Clean targets + ================================================================== --> + + <target name="clean.build"> + <delete dir="build/build.main" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + <delete dir="build/build.test" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + <delete dir="build/build.examples" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + </target> + + <target name="clean.pack" depends="clean.build"> + <delete dir="build/pack" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + </target> + + <target name="clean.dist" depends="clean.pack"> + <delete dir="build/dist" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + <delete dir="build/toolscript" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + </target> + + <target name="clean.doc"> + <delete dir="doc/api" includeemptydirs="yes" + quiet="yes" failonerror="no"/> + </target> + + <target name="clean.all" depends="clean.dist,clean.doc"/> +</project> diff --git a/docs/examples/plugintemplate/doc/README b/docs/examples/plugintemplate/doc/README new file mode 100644 index 0000000000..f3b9e15e97 --- /dev/null +++ b/docs/examples/plugintemplate/doc/README @@ -0,0 +1,42 @@ +Scala compiler plugin template +------------------------------ + +This project is a template that can be used for creating compiler +plugins for the Scala compiler. + + +Installation +------------ +To install the compiler plugin, run "ant install". This will create +an sbaz package for the template plugin and install it in the scala +installation available in your PATH. +The install command will also create a script for running the plugin +as standalone application. The command is called "runplugintemplate" +and available in your scala installation as well. +To uninstall the plugin again, run "and uninstall". + +Alternatively, copy the file build/pack/plugintemplate.jar, generated +by "ant pack", to the directory misc/scala-devel/plugins of your +scala distribution. The scala compiler will then find and integrate +the new plugin. + +Customization +------------- +The following files need to be edited when creating a new plugin +- plugin.properties +- misc/scalac-plugin.xml +- src / test / doc/examples: The source files of the template plugin + are located a package called "plugintemplate". This will most likely + be changed for new plugins. + +When using eclipse for development, make sure "scala-compiler.jar" is +in the Java Build Path: Right-Click the project and select "Properties". +Then go to "Java Build Path" -> "Libraries" and add the jar file +"eclipse/plugins/ch.epfl.lamp.sdt.core[..]/lib/scala-compiler.jar". + +Ant tasks +--------- +"build.xml" defines Ant tasks for building, testing and packing a +plugin. The tests are written using the ScalaTest framework +(http://www.artima.com/scalatest/). +Run the tests using "ant test", or "ant guitest". diff --git a/docs/examples/plugintemplate/doc/examples/plugintemplate/examples/BasicExample.scala b/docs/examples/plugintemplate/doc/examples/plugintemplate/examples/BasicExample.scala new file mode 100644 index 0000000000..d1f6c91cdc --- /dev/null +++ b/docs/examples/plugintemplate/doc/examples/plugintemplate/examples/BasicExample.scala @@ -0,0 +1,8 @@ +package plugintemplate.examples + +/** An example demonstrating the fancy features of the new + * compiler plugin. + */ +class BasicExample { + def foo = () +} diff --git a/docs/examples/plugintemplate/lib/scalatest.jar.desired.sha1 b/docs/examples/plugintemplate/lib/scalatest.jar.desired.sha1 new file mode 100644 index 0000000000..ab3c5ffd2c --- /dev/null +++ b/docs/examples/plugintemplate/lib/scalatest.jar.desired.sha1 @@ -0,0 +1 @@ +462624d9413123e32d073863fa8759457cf8721e ?scalatest.jar diff --git a/docs/examples/plugintemplate/misc/scalac-plugin.xml b/docs/examples/plugintemplate/misc/scalac-plugin.xml new file mode 100644 index 0000000000..bad4e87327 --- /dev/null +++ b/docs/examples/plugintemplate/misc/scalac-plugin.xml @@ -0,0 +1,4 @@ +<plugin> + <name>plugintemplate</name> + <classname>plugintemplate.TemplatePlugin</classname> +</plugin> diff --git a/docs/examples/plugintemplate/plugin.properties b/docs/examples/plugintemplate/plugin.properties new file mode 100644 index 0000000000..0db340cffa --- /dev/null +++ b/docs/examples/plugintemplate/plugin.properties @@ -0,0 +1,10 @@ +scala.home=/Users/luc/scala/dist + +plugin.name=plugintemplate +plugin.commandname=runplugintemplate +plugin.description=A template compiler plugin saying hello to the World +plugin.mainclass=plugintemplate.standalone.Main +plugin.sbazbaseurl=http://scala.epfl.ch/downloads/packages + +version.major=0 +version.minor=1 diff --git a/docs/examples/plugintemplate/src/plugintemplate/PluginProperties.scala b/docs/examples/plugintemplate/src/plugintemplate/PluginProperties.scala new file mode 100644 index 0000000000..e9c2050a29 --- /dev/null +++ b/docs/examples/plugintemplate/src/plugintemplate/PluginProperties.scala @@ -0,0 +1,61 @@ +package plugintemplate + +import java.util.Properties + +/** A utility to load properties of this plugin via the property + * file "plugin.properties" + */ +object PluginProperties { + private val propFilename = "plugin.properties" + + val pluginName = getOrElse("plugin.name", "(name_unknown)") + val pluginDescription = getOrElse("plugin.description", "(plugin description not found)") + val pluginCommand = getOrElse("plugin.commandname", "(command_unknown)") + val versionString = { + val default = "(version_unknown)" + props match { + case Some(p) => + val major = p.getProperty("version.major") + val minor = p.getProperty("version.minor") + if ((major eq null) || (minor eq null)) default + else major +"."+ minor + case None => default + } + } + + private def getOrElse(property: String, default: String) = { + props match { + case Some(p) if (p.getProperty(property) != null) => + p.getProperty(property) + case _ => + default + } + } + + private lazy val props: Option[Properties] = { + /** Running from JAR file: the properties file should be in the + * jar as well + */ + var stream = this.getClass.getResourceAsStream("/"+ propFilename) + if (stream == null) { + /** Running from .class files: expect classfiles to be in + * directory [...]/build/build.main, and [...] to contain + * the properties file. + */ + try { + val current = this.getClass.getClassLoader.getResource(".") + val dir = new java.io.File(current.toURI) + // dir will be [...]/build/build.main/ + stream = new java.io.FileInputStream(dir.getParentFile.getParent +"/"+ propFilename) + } catch { + case _ => () + } + } + if (stream == null) None + else { + val p = new Properties + p.load(stream) + Some(p) + } + } +}
\ No newline at end of file diff --git a/docs/examples/plugintemplate/src/plugintemplate/TemplateComponent.scala b/docs/examples/plugintemplate/src/plugintemplate/TemplateComponent.scala new file mode 100644 index 0000000000..b6e405dcef --- /dev/null +++ b/docs/examples/plugintemplate/src/plugintemplate/TemplateComponent.scala @@ -0,0 +1,33 @@ +package plugintemplate + +import scala.tools.nsc._ +import scala.tools.nsc.plugins.PluginComponent + +/** This class shows how to implement a compiler component that + * can be used in a compiler plugin. + * + * @todo Adapt the name of this class to the plugin, and implement it. + */ +class TemplateComponent(val global: Global) extends PluginComponent { + import global._ + import global.definitions._ + + val runsAfter = "refchecks" + /** The phase name of the compiler plugin + * @todo Adapt to specific plugin. + */ + val phaseName = "plugintemplate" + + def newPhase(prev: Phase) = new Phase(prev) { + def name = phaseName + + /** This method contains the implementation of the compiler + * component + * + * @todo Implementation. + */ + def run { + println("Hello from phase "+ name) + } + } +} diff --git a/docs/examples/plugintemplate/src/plugintemplate/TemplatePlugin.scala b/docs/examples/plugintemplate/src/plugintemplate/TemplatePlugin.scala new file mode 100644 index 0000000000..e79608fe59 --- /dev/null +++ b/docs/examples/plugintemplate/src/plugintemplate/TemplatePlugin.scala @@ -0,0 +1,24 @@ +package plugintemplate + +import scala.tools.nsc.Global +import scala.tools.nsc.plugins.Plugin + +/** A class describing the compiler plugin + * + * @todo Adapt the name of this class to the plugin being + * implemented + */ +class TemplatePlugin(val global: Global) extends Plugin { + /** The name of this plugin. Extracted from the properties file. */ + val name = PluginProperties.pluginName + + /** A short description of the plugin, read from the properties file */ + val description = PluginProperties.pluginDescription + + /** The compiler components that will be applied when running + * this plugin + * + * @todo Adapt to the plugin being implemented + */ + val components=List(new TemplateComponent(global)) +} diff --git a/docs/examples/plugintemplate/src/plugintemplate/standalone/Main.scala b/docs/examples/plugintemplate/src/plugintemplate/standalone/Main.scala new file mode 100644 index 0000000000..6eec249ed7 --- /dev/null +++ b/docs/examples/plugintemplate/src/plugintemplate/standalone/Main.scala @@ -0,0 +1,38 @@ +package plugintemplate.standalone + +import scala.tools.nsc.CompilerCommand +import scala.tools.nsc.Settings + +/** An object for running the plugin as standalone application. + */ +object Main { + def main(args: Array[String]) { + val settings = new Settings + + val command = new CompilerCommand(args.toList, settings, println, false) { + /** The command name that will be printed in in the usage message. + * This is autmatically set to the value of 'plugin.commandname' in the + * file build.properties. + */ + override val cmdName = PluginProperties.pluginCommand + } + + if (!command.ok) + return() + + /** The version number of this plugin is read from the porperties file + */ + if (settings.version.value) { + println(command.cmdName +" version "+ PluginProperties.versionString) + return() + } + if (settings.help.value) { + println(command.usageMsg) + return() + } + + val runner = new PluginRunner(settings) + val run = new runner.Run + run.compile(command.files) + } +} diff --git a/docs/examples/plugintemplate/src/plugintemplate/standalone/PluginRunner.scala b/docs/examples/plugintemplate/src/plugintemplate/standalone/PluginRunner.scala new file mode 100644 index 0000000000..b385581778 --- /dev/null +++ b/docs/examples/plugintemplate/src/plugintemplate/standalone/PluginRunner.scala @@ -0,0 +1,30 @@ +package plugintemplate.standalone + +import scala.tools.nsc.{Global, Settings, SubComponent} +import scala.tools.nsc.reporters.{ConsoleReporter, Reporter} + +/** This class is a compiler that will be used for running + * the plugin in standalone mode. + * + * @todo Adapt to specific plugin. + */ +class PluginRunner(settings: Settings, reporter: Reporter) +extends Global(settings, reporter) { + def this(settings: Settings) = this(settings, new ConsoleReporter(settings)) + + /** The plugin component that should will executed. + * + * @todo Adapt to specific plugin. It is possible to add multiple + * plugin components to run. + */ + val pluginComponent = new TemplateComponent(this) + + override def phaseDescriptors: List[SubComponent] = List( + analyzer.namerFactory, + analyzer.typerFactory, + superAccessors, + pickler, + refchecks, + pluginComponent + ) +} diff --git a/docs/examples/plugintemplate/test/plugintemplate/PluginPropertiesSuite.scala b/docs/examples/plugintemplate/test/plugintemplate/PluginPropertiesSuite.scala new file mode 100644 index 0000000000..72b8ee66c3 --- /dev/null +++ b/docs/examples/plugintemplate/test/plugintemplate/PluginPropertiesSuite.scala @@ -0,0 +1,14 @@ +package plugintemplate.examples + +import org.scalatest.Suite + +class PluginPropertiesSuite extends Suite { + def testProperties() { + expect("A template compiler plugin saying hello to the World") { + PluginProperties.pluginDescription + } + expect("0.1") { + PluginProperties.versionString + } + } +} diff --git a/docs/examples/plugintemplate/test/plugintemplate/TemplatePluginSuite.scala b/docs/examples/plugintemplate/test/plugintemplate/TemplatePluginSuite.scala new file mode 100644 index 0000000000..06916f9dd3 --- /dev/null +++ b/docs/examples/plugintemplate/test/plugintemplate/TemplatePluginSuite.scala @@ -0,0 +1,22 @@ +package plugintemplate + +import org.scalatest.Suite +import org.scalatest.Ignore + +class TemplatePluginSuite extends Suite { + def testName() { + import scala.tools.nsc.{Global, Settings} + import scala.tools.nsc.reporters.ConsoleReporter + val settings = new Settings + val compiler = new Global(settings, new ConsoleReporter(settings)) + val plugin = new TemplatePlugin(compiler) + expect("plugintemplate") { + plugin.name + } + } + + @Ignore + def testFail() { + expect(1) { 2 } + } +} |