diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 25 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Main.scala | 19 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/DocGenerator.scala | 724 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/DocUtil.scala | 82 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/models/Models.scala | 91 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/models/SemanticTokens.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/NameTransformer.scala | 4 |
8 files changed, 666 insertions, 282 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 35373f9914..978bbf1da0 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -32,7 +32,6 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable with CompilationUnits { - // sub-components -------------------------------------------------- object treePrinters extends TreePrinters { @@ -83,7 +82,6 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable if (onlyPresentation) new HashMap[Symbol,String]; else null; - // reporting ------------------------------------------------------- def error(msg: String) = reporter.error(null, msg); @@ -100,6 +98,27 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable def log(msg: Object): unit = if (settings.log contains phase.name) inform("[log " + phase + "] " + msg); + class ErrorWithPosition(val pos : Int, val error : Throwable) extends Error; + + def tryWith[T](pos : Int, body : => T) : T = try { + body; + } catch { + case e : ErrorWithPosition => throw e; + case te: TypeError => throw te; + case e : Error => throw new ErrorWithPosition(pos, e); + case e : RuntimeException => throw new ErrorWithPosition(pos, e); + } + def catchWith[T](source : SourceFile, body : => T) : T = try { + body; + } catch { + case e : ErrorWithPosition => + logError("POS: " + source.dbg(e.pos), e); + throw e.error; + } + + + + def logError(msg: String, t : Throwable): Unit = {}; def abort(msg: String) = throw new Error(msg); @@ -305,7 +324,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable private var curRun: Run = NoRun; override def currentRun: Run = curRun; - def onlyPresentation = false; + def onlyPresentation = settings.doc.value; class Run extends CompilerRun { var currentUnit : CompilationUnit = _; diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index 8a40c8a42c..4ea6108330 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -7,6 +7,8 @@ package scala.tools.nsc; import scala.tools.nsc.util.{Position}; import scala.tools.nsc.reporters.{Reporter, ConsoleReporter}; +import scala.tools.nsc.doc.DocGenerator; + /** The main class for NSC, a compiler for the programming * language Scala. @@ -48,13 +50,24 @@ object Main extends Object with EvalLoop { reporter.info(null, command.usageMsg, true) else { try { - val compiler = new Global(command.settings, reporter); + object compiler extends Global(command.settings, reporter); if (command.settings.resident.value) resident(compiler); else if (command.files.isEmpty) reporter.info(null, command.usageMsg, true) - else - (new compiler.Run) compile command.files; + else { + val run = new compiler.Run; + run compile command.files; + + + if (command.settings.doc.value) { + object generator extends DocGenerator { + val global : compiler.type = compiler; + val outdir = command.settings.outdir.value; + }; + generator.process(run.units); + } + } } catch { case ex @ FatalError(msg) => if (command.settings.debug.value) diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index 26ad1d57a0..20ba58bf29 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -52,6 +52,7 @@ class Settings(error: String => unit) { } else null } + val doc = BooleanSetting("-doc", "Generate documentation"); val debuginfo = BooleanSetting("-g", "Generate debugging info") val nowarnings = BooleanSetting("-nowarn", "Generate no warnings") val noassertions = BooleanSetting("-noassert", "Generate no assertions and assumptions") diff --git a/src/compiler/scala/tools/nsc/doc/DocGenerator.scala b/src/compiler/scala/tools/nsc/doc/DocGenerator.scala index d1d719497a..ae1c8d4bb2 100644 --- a/src/compiler/scala/tools/nsc/doc/DocGenerator.scala +++ b/src/compiler/scala/tools/nsc/doc/DocGenerator.scala @@ -1,120 +1,469 @@ package scala.tools.nsc.doc; import scala.tools.nsc._; -import java.io.File; +import java.io._; import scala.tools.nsc.models._; import scala.collection.immutable._; import scala.xml._; abstract class DocGenerator extends Models { import global._; + import DocUtil._; + def outdir : String; + def contentFrame = "contentFrame"; + def classesFrame = "classesFrame"; + def modulesFrame = "modulesFrame"; + def emptyMap = ListMap.Empty[Kind,TreeSet[HasTree]]; - def dquote(str : String) = Text("\"" + str + "\""); - val header = <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/> - <meta name="generator" content="scaladoc (1.4.0.4)"/> - <link rel="stylesheet" type="text/css" href="style.css"/> - <script type="text/javascript" src="script.js"></script>; + override def acceptPrivate = false; - def page = <HTML></HTML>; + abstract class Frame extends UrlContext { + def path : String; // relative to outdir + def relative : String = { + assert(path != null); + var idx = 0; + var ct = ""; + while (idx != -1) { + idx = path.indexOf('/', idx); + //System.err.println(path + " idx=" + idx); + ct = ct + (if (idx != -1) "../" else ""); + idx = idx + (if (idx == -1) 0 else 1); + } + ct; + } + + def body : NodeSeq; + def title : String; + def save(nodes : NodeSeq) = { + val path0 = outdir + "/" + path + ".html"; + System.err.println("Writing to " + path0); + val file = new File(path0); + val parent = file.getParentFile(); + if (!parent.exists()) parent.mkdirs(); + val writer = new FileWriter(file); + val str = dtype + "\n" + nodes.toString(); + writer.write(str, 0, str.length()); + writer.close(); + } + def urlFor(sym : Symbol, target : String) : NodeSeq = + aref(urlFor(sym), target, sym.nameString); + + + def urlFor0(sym : Symbol, orig : Symbol) : String = { + (if (sym == NoSymbol) { + "XXX"; + } else if (sym.owner.isPackageClass) sym.fullNameString('/'); + else urlFor0(sym.owner, orig) + "." + Utility.escape(sym.nameString)) + (sym match { + case msym : ModuleSymbol => "$object"; + case csym : ClassSymbol => ""; + case _ => + System.err.println("XXX: class or object " + orig + " not found in " + sym); + "XXXXX"; + + }) + } + def urlFor(sym : Symbol) : String = { + sym match { + case msym : ModuleSymbol => urlFor0(sym,sym) + ".html"; + case csym : ClassSymbol => urlFor0(sym,sym) + ".html"; + case _ => urlFor(sym.owner) + "#" + Utility.escape(sym.nameString); + } + } + def hasBody = true; + + save(page(title, body, hasBody)); + } + + abstract class ListModuleFrame extends Frame { + val path = "modules"; + val title = "List of all packages"; + def modules : TreeMap[String,ModuleClassSymbol]; + def body : NodeSeq = { + val x = div0("Scala 2") concat + aref("all-classes.html", classesFrame, "All objects and classes"); + val y = <P/><B>Packages</B> + <TABLE class="list"><TR><TD style="white-space:nowrap;"> + { { + for (val top <- modules.elements.toList) yield + {br(aref(urlFor(top._2), classesFrame, top._2.fullNameString('.')))}; + } } + </TD></TR></TABLE>; + x.concat(y); + } + } + + abstract class ListModuleContentFrame extends Frame { + val path = "root-content"; + val title = "All Packages"; + def modules : TreeMap[String,ModuleClassSymbol]; + def body : NodeSeq = { + <SPAN><DIV class="page-title"> + Scala 2 + <BR/>API Specification + </DIV> + This document is the API specification for Scala 2. + <P/><HR/> + <TABLE cellpadding="3" class="member"> + <TR><TD colspan="2" class="title"> + Package Summary + </TD> + </TR>{ { + for (val top <- modules.elements.toList) yield + <TR><TD class="signature"> + <CODE>{Text("package")} + {(aref(top._2.fullNameString('/') + "$content.html", "_self", top._2.fullNameString('.')))}</CODE> + </TD></TR>; + } } + </TABLE> + </SPAN>; + } + } + + abstract class ListClassFrame extends Frame { + def classes : ListMap[Kind,TreeSet[HasTree]]; + + def navLabel : String; + + def body : NodeSeq = { + val nav = <TABLE class="navigation"><TR><TD valign="top" class="navigation-links"> + {aref(path + ".html", contentFrame, navLabel)} + </TD></TR></TABLE><P/>; + + + val body = <SPAN> { { for (val kind <- KINDS; classes.contains(kind)) yield { + val x = <B>{Text(pluralFor(kind))}</B>; + + val y = <TABLE class="list"><TR><TD style="white-space;nowrap;"> + { { + for (val mmbr <- classes(kind).toList) yield + br(urlFor(mmbr.tree.symbol, contentFrame)); + } } + </TD></TR></TABLE>; + val ret :NodeSeq = x.concat(y); + ret; + } } } </SPAN>; + + nav.concat(body); + } + } + + abstract class ContentFrame0 extends Frame { + def extendsFor(mmbr : HasTree) : NodeSeq = mmbr match { + case mmbr : ImplMod => + if (!mmbr.treey.impl.parents.isEmpty) + <SPAN><dd><code>{Text(" extends ")}</code> + {forType(mmbr.treey.impl.parents.head.tpe)}</dd> + { { for (val parent <- mmbr.treey.impl.parents.tail) + yield <dd><code>{Text(" with ")}</code> + {forType(parent.tpe)}</dd>; + } } </SPAN>; + else NodeSeq.Empty; + case _ => NodeSeq.Empty; + } + def fullHeader(mmbr : HasTree) : NodeSeq = <SPAN>{ { + if (!mmbr.isInstanceOf[ImplMod]) { + <a name = {Utility.escape(mmbr.tree.symbol.nameString)}></a>; + } else NodeSeq.Empty; + } }<DL><DT> + { { for (val str <- stringsFor(mmbr.mods)) yield (Text(str + " ")) } } + <CODE>{ Text(codeFor(mmbr.kind)) }</CODE> + <EM>{ Text(mmbr.tree.symbol.nameString) }</EM> + { typesFor(mmbr) }{ argsFor(mmbr)}{resultFor(mmbr) } + </DT> { extendsFor(mmbr) } + </DL> { fullComment(mmbr) } <HR/> + { lists(mmbr) } </SPAN>; + + def lists(mmbr : HasTree) = mmbr match { + case cmod : ImplMod => <SPAN>{ listMembersShort(mmbr) } + { listMembersFull (mmbr) }</SPAN> + case _ => NodeSeq.Empty; + } + + + def listMembersShort(mmbr : HasTree) : NodeSeq = if (mmbr.isInstanceOf[Composite]) { + val map = organize(mmbr.asInstanceOf[Composite], emptyMap); + <SPAN> { { + for (val kind <- KINDS; map.contains(kind)) yield { + val x = <TABLE cellpadding="3" class="member"> + <TR><TD colspan="2" class="title">{Text(labelFor(kind))} Summary</TD></TR> + { { + for (val mmbr <- map(kind).toList) yield shortHeader(mmbr); + } } + </TABLE>; + br(x); + } + } } </SPAN> + } else NodeSeq.Empty; + + def listMembersFull(mmbr : HasTree) : NodeSeq = if (mmbr.isInstanceOf[Composite]) { + val map = organize(mmbr.asInstanceOf[Composite], emptyMap); + val mmbrx = mmbr; + val pathx = path; + for (val kind0 <- OBJECT :: CLASS :: Nil; map.contains(kind0)) for (val mmbr <- map(kind0)) { + new ContentFrame { + def clazz = mmbr.asInstanceOf[ImplMod]; + def kind = kind0; + def title = labelFor(kind0) + " " + mmbr.tree.symbol.nameString + " in " + codeFor(mmbrx.kind) + " " + mmbr.tree.symbol.owner.fullNameString('.'); + } + } + <SPAN> { { + for (val kind <- KINDS; map.contains(kind) && kind != OBJECT && kind != CLASS) yield { + val header = <table cellpadding="3" class="member-detail"> + <tr><td class="member-title">{Text(labelFor(kind))} Detail</td></tr> + </table>; + val body = for (val mmbr <- map(kind).toList) yield <SPAN>{fullHeader(mmbr)}</SPAN>; + header.concat(body); + } + } } </SPAN>; + } else NodeSeq.Empty; + + def shortHeader(mmbr : HasTree) : NodeSeq = { + <TR> + <TD valign="top" class="modifiers"> + { { for (val str <- stringsFor(mmbr.mods)) yield <CODE>{(Text(str + " "))}</CODE>; } } + </TD> + <TD class="signature"> + <CODE>{Text(codeFor(mmbr.kind))}</CODE> + <EM>{urlFor(mmbr.tree.symbol, contentFrame)}</EM> + { typesFor(mmbr) } + { argsFor(mmbr) } + {resultFor(mmbr) } + <BR>{shortComment(mmbr)}</BR> + </TD> + </TR>; + } + + + def fullComment(mmbr : HasTree) : NodeSeq = { + if (comments.contains(mmbr.tree.symbol)) + comment(comments(mmbr.tree.symbol), false) else NodeSeq.Empty; + }; + def shortComment(mmbr : HasTree) : NodeSeq = { + if (comments.contains(mmbr.tree.symbol)) + comment(comments(mmbr.tree.symbol), true) else NodeSeq.Empty; + }; + def ifT (cond : Boolean, nodes : NodeSeq) = if (cond) nodes else NodeSeq.Empty; + def ifT (tree : Tree, nodes : NodeSeq, before : Boolean) = { + if (tree != EmptyTree && + tree.tpe.symbol != definitions.AnyClass && + tree.tpe.symbol != definitions.AllClass) { + if (before) nodes.concat(forTree(tree)); + else forTree(tree).concat(nodes); + } else NodeSeq.Empty; + } + + def forType(tpe : Type) : NodeSeq = + urlFor(tpe.symbol, contentFrame); + + def forTree(tree : Tree) : NodeSeq = tree match { + case vdef : ValDef => + Text(vdef.symbol.name.toString()).concat(Text(" : ")).concat(forTree(vdef.tpt)); + case sel : Select => forTree(sel.qualifier).concat(Text(sel.symbol.nameString)); + case tree : AbsTypeDef => + ifT(tree.lo, Text(" <: "), false). + concat(Text(tree.symbol.nameString)).concat(ifT(tree.hi, Text(" <: "), true)); + case tpt : TypeTree => urlFor(tpt.tpe.symbol, contentFrame); + case id : Ident => Text("YY: " + id.symbol.nameString); + case EmptyTree => NodeSeq.Empty; + case _ => Text("XX=" + tree.getClass() + " " + tree.toString()); + } + def forTrees(trees : List[Tree]) : NodeSeq = { + if (trees.isEmpty) NodeSeq.Empty; + else { + val head = forTree(trees.head); + head.concat(if (trees.tail.isEmpty) NodeSeq.Empty + else Text(", ")).concat(forTrees(trees.tail)); + } + } + + def surround(open : String, close : String, node : NodeSeq) : NodeSeq = + Text(open).concat(node).concat(Text(close)); + + def typesFor(ht : HasTree) : NodeSeq = { + val tparams = ht.tree match { + case cdef : ClassDef => cdef.tparams; + case ddef : DefDef => ddef.tparams; + case adef : AliasTypeDef => adef.tparams; + case _ => Nil; + } + if (tparams.isEmpty) Text(""); + else surround("[", "]", forTrees(tparams)); + } + def argsFor(ht : HasTree) : NodeSeq = ht.tree match { + case ddef : DefDef => + if (!ddef.vparamss.isEmpty && + (!ddef.vparamss.tail.isEmpty || !ddef.vparamss.head.isEmpty)) { + val nodes = for (val vparams <- ddef.vparamss) + yield surround("(", ")", forTrees(vparams)); + nodes.flatMap(x => x.asList); + } else NodeSeq.Empty; + case _ => NodeSeq.Empty; + } + def resultFor(ht : HasTree) : NodeSeq = ht.tree match { + case vdef : ValOrDefDef => + if (!vdef.symbol.nameString.equals("this")) + Text(" : ").concat(forTree(vdef.tpt)); + else NodeSeq.Empty; + case _ => NodeSeq.Empty; + } + } + + abstract class ListClassContentFrame extends ContentFrame0 { + def classes : ListMap[Kind,TreeSet[HasTree]]; + def module : ModuleClassSymbol; + + def path = module.fullNameString('/') + "$content"; + def title = "All Classes and Objects in " + module.fullNameString('.'); + + def body : NodeSeq = { + <SPAN><DIV class="page-title"> + Scala 2 + <BR/>API Specification + </DIV> + This document is the API specification for Scala 2. + <P/> + { { + for (val kind <- KINDS; classes.contains(kind)) yield { + <SPAN><HR/><TABLE cellpadding="3" class="member"> + <TR><TD colspan="2" class="title"> + {labelFor(kind)} Summary + </TD></TR>{ { + for (val mmbr <- classes(kind).toList) yield shortHeader(mmbr); + } } + </TABLE></SPAN> + } + } } + </SPAN>; + } + } - val emptyMap = ListMap.Empty[Kind,TreeSet[HasTree]]; - def process(units : Iterator[CompilationUnit], outdir : String) : Unit = { - val outdir0 = new File(outdir); - if (!outdir0.exists()) outdir0.mkdir(); + abstract class ContentFrame extends ContentFrame0 { + def clazz : ImplMod; + def kind : Kind; + def body : NodeSeq = <SPAN>{navigation}{header0}{fullHeader(clazz)}</SPAN>; + + final def path = urlFor0(clazz.tree.symbol,clazz.tree.symbol); + + def navigation : NodeSeq = + <TABLE class="navigation"> + <TR> + <TD valign="top" class="navigation-links"> + <TABLE><TR> + <TD class="navigation-enabled">{aref("root-page.html", "_self", "Overview")}</TD> + <TD class="navigation-enabled">{aref("index.html" , "_self", "Index" )}</TD> + <TD class="navigation-enabled">{aref("help.html" , "_self", "Help" )}</TD> + </TR></TABLE> + </TD> + <TD align="right" valign="top" style="white-space:nowrap;" rowspan="2"> + {div0("Scala 2")} + </TD> + </TR> + <TR><TD></TD></TR> + </TABLE>; + + def header0 : NodeSeq = <SPAN> + <HR/> in {aref(urlFor(clazz.tree.symbol.owner), "_self", clazz.tree.symbol.owner.fullNameString('.'))} + <DIV class="entity"> + {Text(codeFor(kind))} + <SPAN class="entity">{Text(clazz.tree.symbol.nameString)}</SPAN> + </DIV><HR/> + </SPAN>; + + + + + } + + def process(units : Iterator[CompilationUnit]) : Unit = { var members = emptyMap; - var topLevel = ListMap.Empty[ModuleSymbol,ListMap[Kind,TreeSet[HasTree]]]; + + var topLevel = ListMap.Empty[ModuleClassSymbol,ListMap[Kind,TreeSet[HasTree]]]; for (val unit <- units) { val sourceMod = new SourceMod(unit); for (val mmbr <- sourceMod.members) mmbr.tree match { case cdef: ImplDef => assert(cdef.symbol.owner != NoSymbol); - val sym = cdef.symbol.owner.asInstanceOf[ModuleSymbol]; + val sym = cdef.symbol.owner.asInstanceOf[ModuleClassSymbol]; if (!topLevel.contains(sym)) topLevel = topLevel.update(sym, emptyMap); topLevel = topLevel.update(sym, organize0(mmbr, topLevel(sym))); case _ => throw new Error("unknown: " + mmbr.tree + " " + mmbr.tree.getClass()); } } - var packages = new TreeMap[String,ModuleSymbol]; - for (val top <- topLevel.elements) - packages = packages.insert(top._1.fullNameString, top._1); - - - val packageFrame = <HTML> - <HEAD><TITLE>List of modules</TITLE> - {header} - </HEAD> - <body> - <div class="doctitle-larger"> - Scala<br/>2.0 - </div> - <a href="module-page.html" target="classesFrame">All objects and classes</a><p/> - <b>Modules</b> - <table class="list"> - <tr> - <td style="white-space:nowrap;"> - { { - for (val top <- packages.elements) - yield urlFor0(top._2, "classesFrame"); - } } - </td></tr></table></body></HTML>; - - - System.out.println("PACKAGE_FRAME"); - System.out.println(packageFrame); - - - // output HTML for each package. + + val modules0 = { + var modules0 = new TreeMap[String,ModuleClassSymbol]; + for (val top <- topLevel.elements) + modules0 = modules0.insert(top._1.fullNameString, top._1); + modules0; + }; + + new ListModuleFrame { + def modules = modules0; + }; + new ListModuleContentFrame { + def modules = modules0; + }; + + new ListClassFrame { + def classes = { + var allClasses = emptyMap; + for (val top <- topLevel.elements) + allClasses = merge(allClasses, top._2); + allClasses; + } + def title = "List of all classes and objects"; + def path = "all-classes"; + def navLabel = "root-page"; + }; + // class from for each module. for (val top <- topLevel.elements) { - val sym = top._1; + val module = top._1; val members = top._2; - val index = {process(members, sym)}; - - System.out.println("SAVE-TO: " + sym); - System.out.println(index); + new ListClassFrame { + def title = "List of classes and objects in package " + module.fullNameString('.'); + def classes = top._2; + def path = module.fullNameString('/'); + def navLabel = module.fullNameString('.'); + }; + val module0 = module; + new ListClassContentFrame { + def classes = top._2; + def module = module0; + }; + + // do root frame for each class and object + for (val kind <- members.elements) for (val mmbr <- kind._2.toList) { + val kind0 = kind._1; + new ContentFrame { + def title = labelFor(kind0) + " " + mmbr.tree.symbol.nameString + " in package " + mmbr.tree.symbol.owner.fullNameString('.'); + def clazz = mmbr.asInstanceOf[ImplMod]; + def kind = kind0; + } + } } - } - def nameFor0(sym : Symbol) : NodeSeq = Text(sym.fullNameString); - def urlFor0(sym : Symbol, target : String) : NodeSeq = - <a href={urlFor1(sym)} target={("\"" + target + "\"")}>{nameFor0(sym)}</a><br/>; + new Frame { + def title = "Scala Library Documentation"; + def body = index; + def path = "index"; + override def hasBody = false; + }; - def urlFor2(sym : Symbol) : String = { - if (sym == sym.toplevelClass) ""; - else { - val rest = urlFor2(sym.owner); - val rest0 = if (rest.equals("")) rest else rest + "."; - rest0 + sym.nameString; - } } - def urlFor1(sym : Symbol) : String = sym match { - case _ : ModuleSymbol => - ("\"" + sym.fullNameString('/') + "/module-page.html\""); - case csym : ClassSymbol => - if (csym == csym.toplevelClass) - "\"" + csym.fullNameString('/') + "-class-page.html\""; - else urlFor1(sym.toplevelClass) + "#" + urlFor2(sym); - case _ => urlFor1(sym.toplevelClass) + "#" + urlFor2(sym); - } - def process(members : ListMap[Kind,TreeSet[HasTree]], sym : Symbol) : NodeSeq = { - for (val kind <- KINDS; members.contains(kind)) yield process(kind, members(kind), sym); - - urlFor0(sym, "classesFrame"); - - }; - def organize(c : Composite, map0 : ListMap[Kind,TreeSet[HasTree]]) = { var map = map0; + //System.err.println("MEMBERS: " + c.members.toList); for (val mmbr <- c.members.toList) map = organize0(mmbr, map); map; } @@ -122,188 +471,83 @@ abstract class DocGenerator extends Models { var map = map0; if (!map.contains(mmbr.kind)) map = map.update(mmbr.kind, new TreeSet[HasTree]); + val sz = map(mmbr.kind).size; map = map.update(mmbr.kind, map(mmbr.kind) + mmbr); + if (map(mmbr.kind).size == sz) + System.err.println(""+mmbr + " not added"); map; } - def process(kind : Kind, set : TreeSet[HasTree], sym : Symbol) : Node = { - val ret = - <table cellpadding="3" class="member"> - <tr> - <td colspan="2" class="title"> - { { labelFor(kind) + " Summary"; } } - </td> - </tr> - { { for (val mmbr <- set.toList) yield process(mmbr, sym); } } - </table>; - ret; - } - def stringsFor(mods : Modifiers) = { - var modString : List[String] = Nil; - if (mods . isPrivate ) modString = "private" :: modString; - if (mods . isProtected) modString = "protected" :: modString; - if (mods . isOverride ) modString = "override" :: modString; - if (mods . isAbstract ) modString = "abstract" :: modString; - if (mods . isCase ) modString = "case" :: modString; - if (mods . isSealed ) modString = "sealed" :: modString; - if (mods . isFinal ) modString = "final" :: modString; - if (mods . isMixin ) modString = "mixin" :: modString; - modString; - } - - - def targetFor(ht : HasTree) : String = { - // compute a URL. - "Foo"; - } - def forSymbol(symbol : Symbol, tpe : Type) : NodeSeq = - Text(symbol.nameString); - - - def ifT (cond : Boolean, nodes : NodeSeq) = if (cond) nodes else NodeSeq.Empty; - def ifT (tree : Tree, nodes : NodeSeq, before : Boolean) = - if (tree != EmptyTree) { - if (before) nodes.concat(forTree(tree)); - else forTree(tree).concat(nodes); - } else NodeSeq.Empty; - - def forTree(tree : Tree) : NodeSeq = tree match { - case vdef : ValDef => - Text(vdef.symbol.name.toString()).concat(Text(" : ")).concat(forTree(vdef.tpt)); - case id : Ident => forSymbol(id.symbol, id.tpe); - case sel : Select => forTree(sel.qualifier).concat(forSymbol(sel.symbol, sel.tpe)); - case tree : AbsTypeDef => - ifT(tree.lo, Text(" <: "), true). - concat(forSymbol(tree.symbol, tree.tpe)).concat(ifT(tree.hi, Text(" <: "), false)); - case EmptyTree => NodeSeq.Empty; - case _ => Text("XX=" + tree.toString()); - } - def forTrees(trees : List[Tree]) : NodeSeq = { - if (trees.isEmpty) NodeSeq.Empty; - else { - val head = forTree(trees.head); - head.concat(if (trees.tail.isEmpty) NodeSeq.Empty else Text(", ")).concat(forTrees(trees.tail)); - } - } - - def surround(open : String, close : String, node : NodeSeq) : NodeSeq = - Text(open).concat(node).concat(Text(close)); + def parse(str : String) : NodeSeq = { + new SpecialNode { + def label = "#PCDATA"; + def toString(sb:StringBuffer): StringBuffer = { + sb.append(str.trim()); + sb; + } - def typesFor(ht : HasTree) : NodeSeq = { - val tparams = ht.tree match { - case cdef : ClassDef => cdef.tparams; - case ddef : DefDef => ddef.tparams; - case adef : AliasTypeDef => adef.tparams; - case _ => Nil; } - if (tparams.isEmpty) Text(""); - else surround("[", "]", forTrees(tparams)); - } - def argsFor(ht : HasTree) : NodeSeq = ht.tree match { - case ddef : DefDef => - val nodes = for (val vparams <- ddef.vparamss) - yield surround("(", ")", forTrees(vparams)); - nodes.flatMap(x => x.asList); - case _ => NodeSeq.Empty; - } - def urlFor(ht : HasTree) : String = - "\"unknown\""; - - def nameFor(ht : HasTree) : NodeSeq = - <A href={ urlFor(ht) } target="_self"> { forSymbol(ht.tree.symbol, null) } </A>; - - def resultFor(ht : HasTree) : NodeSeq = ht.tree match { - case vdef : ValOrDefDef => - Text(" : ").concat(forTree(vdef.tpt)); - case cdef : ImplDef => - if (cdef.impl.parents.isEmpty) NodeSeq.Empty; - else Text("extends ").concat(forTrees(cdef.impl.parents)); - case _ => NodeSeq.Empty; - } + /* + import java.io.StringReader; + import org.xml.sax.InputSource; + val isrc1 = new InputSource(new StringReader(str)); + val parsedxml1 = XML.load(isrc1); + if (parsedxml1 == null) Text("BAD_COMMENT???"); + else parsedxml1; + */ + }; def comment(comment : String, isShort : Boolean) : NodeSeq = { var ret : List[Node] = Nil; - if (comment != null) { - // strip out any stars. - var comment0 = comment.trim(); - assert(comment0.startsWith(JDOC_START)); - comment0 = comment0.substring(JDOC_START.length()); - assert(comment0.endsWith(JDOC_END)); - comment0 = comment0.substring(0, comment0.length() - JDOC_END.length()); - var idx = 0; - while (idx != -1) { - idx = comment0.indexOf('*', idx); - if (idx != -1) - comment0 = comment0.substring(0, idx) + - comment0.substring(idx + 1, comment0.length()); - } - val tokenizer = new java.util.StringTokenizer(comment0, "@"); - val body = tokenizer.nextToken(); - - var attributes : List[String] = Nil; - if (!isShort) while (tokenizer.hasMoreElements()) - attributes = attributes ::: (tokenizer.nextToken() :: Nil); - val node = <BR> { Text(comment) } </BR>; - val nodes = { { for (val a <- attributes) yield <BR> { Text(a) } </BR>; } }; - val nodes0 : NodeSeq = node :: nodes; - nodes0; - } else NodeSeq.Empty; + assert(comment != null); + // strip out any stars. + var comment0 = comment.trim(); + assert(comment0.startsWith(JDOC_START)); + comment0 = comment0.substring(JDOC_START.length()); + assert(comment0.endsWith(JDOC_END)); + comment0 = comment0.substring(0, comment0.length() - JDOC_END.length()); + var idx = 0; + while (idx != -1) { + idx = comment0.indexOf('*', idx); + if (idx != -1) + comment0 = comment0.substring(0, idx) + + comment0.substring(idx + 1, comment0.length()); + } + val tokenizer = new java.util.StringTokenizer(comment0, "@"); + val body = tokenizer.nextToken(); + var attributes : List[Tuple2[String,String]] = Nil; + if (!isShort) while (tokenizer.hasMoreElements()) { + val attr = tokenizer.nextToken(); + val div = attr.indexOf(' '); + val tuple = if (div == -1) new Tuple2(attr,""); + else new Tuple2(attr.substring(0, div), attr.substring(div + 1, attr.length())); + attributes = attributes ::: (tuple :: Nil); + } + if (isShort) <SPAN>{parse(body)}</SPAN>; + else <SPAN><DL><DD>{parse(body)}</DD></DL><DL> + { { + for (val attr <- attributes) yield + <DT style="margin-top:10px;"><B>{Text(attr._1 + ":")}</B></DT> + <DD>{(parse(attr._2))}</DD>; + } } </DL></SPAN>; }; - def process(ht : HasTree, sym : Symbol) : scala.xml.Node = { - val comment0 = if (comments.contains(ht.tree.symbol)) - comments(ht.tree.symbol) else null; - - - val index = - <tr> - <td valign="top" class="modifiers"> - - <code>{ { - (for (val mod <- stringsFor(ht.mods)) yield Text(mod + " ")); - } }</code> - </td> - <td class="signature"> - <code> - { labelFor(ht.kind).toLowerCase() } - { nameFor(ht) } - { typesFor(ht) } - { argsFor(ht) } - {resultFor(ht) } - </code> - { comment(comment0, true) } - </td> - </tr>; - - val body = <X></X>; - - - - + val index = { + <frameset cols="25%, 75%"> + <frameset rows="50%, 50%"> + <frame src="modules.html" name={modulesFrame}></frame> + <frame src="all-classes.html" name={classesFrame}></frame> + </frameset> + <frame src="root-content.html" name={contentFrame}></frame> + </frameset>; + } + val root = <b></b>; - index; - } -/* - val index0 = <HTML> - <HEAD><TITLE>API Documentation</TITLE></HEAD> - <FRAMESET cols="20%,80%" title="" onLoad="top.loadFrames()"> - <FRAMESET rows="30%,70%" title="" onLoad="top.loadFrames()"> - <FRAME src="overview-frame.html" name="packageListFrame" title="All Packages"> - <FRAME src="allclasses-frame.html" name="packageFrame" title="All classes and interfaces (except non-static nested types)"> - </FRAMESET> - <FRAME src="overview-summary.html" name="classFrame" title="Package, class and interface descriptions" scrolling="yes"> - </FRAMESET> - </HTML>; -*/ - - def index = { - val index0 = <HTML></HTML>; - } private val JDOC_START = "/**"; private val JDOC_END = "*/"; diff --git a/src/compiler/scala/tools/nsc/doc/DocUtil.scala b/src/compiler/scala/tools/nsc/doc/DocUtil.scala new file mode 100644 index 0000000000..baadcab546 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/DocUtil.scala @@ -0,0 +1,82 @@ +package scala.tools.nsc.doc; + +import scala.xml._; +import scala.collection.immutable._; +import java.io._; + +object DocUtil { + + def dquote(str : String) : NodeSeq = { + DQUOTE :: Text(str) :: DQUOTE :: Nil; + + } + object DQUOTE extends SpecialNode { + + def toString(sb:StringBuffer) = { + sb.append("\""); sb; + } + def label = "#PCDATA"; + + } + def br(nodes: NodeSeq) : NodeSeq = { + val x = <BR/>; + nodes.concat(x); + } + + + + + + mixin abstract class UrlContext { + + def relative : String; + def aref(href0: String, target : String, text : String) : NodeSeq = { + val href = Utility.escape(href0); + if (target.indexOf('<') != -1) throw new Error(target); + + val t0 = Text(text); + + <a href={(relative + href)} target={(target)}>{t0}</a>; + } + val header = <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/> + <meta name="generator" content="scaladoc (1.4.0.4)"/> + <link rel="stylesheet" type="text/css" href={ relative + "style.css" }/> + <script type="text/javascript" src={relative + "script.js"}></script>; + + def body0(hasBody : Boolean, nodes : NodeSeq) : NodeSeq = + if (!hasBody) nodes; else <BODY>{nodes}</BODY>; + + val dtype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"; + + def page(title : String, body : NodeSeq, hasBody : Boolean) : NodeSeq = + <HTML> + <HEAD><TITLE>{Text(title)}</TITLE> + {header} + </HEAD> + {body0(hasBody, body)} + </HTML>; + + } + + + + + def div0(title : String) : NodeSeq = <DIV class="doctitle-larger">{Text(title)}</DIV>; + + + def merge[T](ts0 : TreeSet[T], ts1 : TreeSet[T]): TreeSet[T] = { + var ts = ts0; + for (val t <- ts1.toList) ts = ts + t; + ts; + } + def merge[T,S <: Ordered[S]](ts0 : ListMap[T,TreeSet[S]], ts1 : ListMap[T,TreeSet[S]]): + ListMap[T,TreeSet[S]] = { + var ts = ts0; + for (val t <- ts1.elements) { + if (!ts.contains(t._1)) + ts = ts.update(t._1, new TreeSet[S]); + ts = ts.update(t._1, merge(ts(t._1), t._2)); + } + ts; + } +} diff --git a/src/compiler/scala/tools/nsc/models/Models.scala b/src/compiler/scala/tools/nsc/models/Models.scala index 0dce3da399..9f2eca3164 100644 --- a/src/compiler/scala/tools/nsc/models/Models.scala +++ b/src/compiler/scala/tools/nsc/models/Models.scala @@ -12,7 +12,10 @@ abstract class Models { val global : Global; import global._; + def acceptPrivate = true; + abstract class Kind {} + object CONSTRUCTOR extends Kind; object OBJECT extends Kind; object CLASS extends Kind; object TRAIT extends Kind; @@ -22,7 +25,7 @@ abstract class Models { object ARG extends Kind; object TPARAM extends Kind; - val KINDS = TPARAM :: CLASS :: TRAIT :: OBJECT :: VAL :: VAR :: DEF :: Nil; + val KINDS = CONSTRUCTOR :: TPARAM :: CLASS :: TRAIT :: OBJECT :: VAL :: VAR :: DEF :: Nil; def labelFor(kind : Kind) : String = kind match { case OBJECT => "Object"; @@ -33,13 +36,39 @@ abstract class Models { case VAR => "Var"; case ARG => "Arg"; case TPARAM => "Type"; + case CONSTRUCTOR => "Constructor"; }; + def stringsFor(mods : Modifiers) = { + var modString : List[String] = Nil; + if (mods . isPrivate ) modString = "private" :: modString; + if (mods . isProtected) modString = "protected" :: modString; + if (mods . isOverride ) modString = "override" :: modString; + if (mods . isAbstract ) modString = "abstract" :: modString; + if (mods . isCase ) modString = "case" :: modString; + if (mods . isSealed ) modString = "sealed" :: modString; + if (mods . isFinal ) modString = "final" :: modString; + if (mods . isMixin ) modString = "mixin" :: modString; + modString; + } + def codeFor(kind : Kind) : String = kind match { + case CONSTRUCTOR => codeFor(DEF); + case _ => labelFor(kind).toLowerCase(); + } + + def pluralFor(kind : Kind) : String = kind match { + case CLASS => "Classes"; + case _ => labelFor(kind) + "s"; + }; + def kindOf(term0 : Symbol) = { if (term0.isVariable) VAR; else if (term0.isValueParameter) ARG; - else if (term0.isMethod) DEF; + else if (term0.isMethod) { + if (term0.nameString.equals("this")) CONSTRUCTOR; + else DEF; + } else if (term0.isClass) CLASS; else if (term0.isModule) OBJECT; else if (term0.isValue ) VAL; @@ -90,6 +119,10 @@ abstract class Models { ret; } + def mods1(tree: Tree) = tree match { + case mdef : MemberDef => mdef.mods + case _ => NoMods + } abstract class HasTree(val parent : Composite) extends Model with Ordered[HasTree] { var tree : Tree = _; @@ -99,39 +132,20 @@ abstract class Models { } def replacedBy(tree0 : Tree) : Boolean = true; def text : String = textFor(tree); - def mods = tree match { - case mdef : MemberDef => mdef.mods - case _ => NoMods - } + var mods0 = NoMods; - override def toString() : String = tree.symbol.toString(); + def mods = if (mods0 != NoMods) mods0 else mods1(tree); + + override def toString() : String = tree.toString(); def compareTo [b >: HasTree <% Ordered[b]](that: b): Int = that match { - case ht : HasTree => toString().compareTo(ht.toString()); + case ht : HasTree => + val result = tree.symbol.nameString.compareTo(ht.tree.symbol.nameString); + if (result != 0) result; + else toString().compareTo(ht.toString()); } def kind = kindOf(tree.symbol); - - /* - public static String getText(Trees$Tree tree) { - if (tree instanceof Trees$ValOrDefDef) { - if (tree instanceof Trees$DefDef) { - Trees$DefDef ddef = (Trees$DefDef) tree; - ret += (listToString(ddef.tparams(), "[", "]", TYPE_E2S) + - listToString(ddef.vparamss(), "", "", PARAM_E2S)); - } - Trees$ValOrDefDef vdef = (Trees$ValOrDefDef) tree; - ret += (" : " + vdef.tpt()); - } - if (tree instanceof Trees$AbsTypeDef) { - Trees$AbsTypeDef tp = (Trees$AbsTypeDef) tree; - ret += (tp.hi() != null ? " <: " + tp.hi() : "") + - (tp.lo() != null ? " >: " + tp.lo() : ""); - } - return ret; - }*/ - - override def add(from : Composite, model : HasTree) : Unit = { parent.add(from, model); } override def remove(from : Composite, model : HasTree) : Unit = { parent.remove(from, model); } } @@ -189,6 +203,8 @@ abstract class Models { if (mmbr2 != null) { var found = false; for (val mmbr <- members) if (!found && mmbr.replacedBy(mmbr2)) { + //System.err.println("REPLACE: " + mmbr + " with " + mmbr2); + mmbr.mods0 = mods1(mmbr1); found = true; updated = mmbr.update(mmbr2) || updated; marked += mmbr; @@ -197,7 +213,9 @@ abstract class Models { updated = true; val add = modelFor(mmbr2, this); add.update(mmbr2); + val sz = members.size; members += (add); + assert(members.size == sz + 1); marked += add; } } @@ -217,7 +235,7 @@ abstract class Models { override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[MemberDef]) { val tree1 = tree0.asInstanceOf[MemberDef]; - treex.name == tree1.name; + treex.toString().equals(tree1.toString()); } else false; override def update(tree0 : Tree): Boolean = { @@ -262,7 +280,8 @@ abstract class Models { def treey = tree.asInstanceOf[ImplDef]; override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ImplDef]); override def isMember(tree : Tree) : Boolean = (super.isMember(tree) || - (tree.isInstanceOf[ValOrDefDef] + (tree.isInstanceOf[ValOrDefDef] && + (acceptPrivate || !tree.asInstanceOf[ValOrDefDef].mods.isPrivate) /* && !tree.asInstanceOf[ValOrDefDef].mods.isPrivate */ /* && !tree.asInstanceOf[ValOrDefDef].mods.isAccessor */) || tree.isInstanceOf[AliasTypeDef]); @@ -273,13 +292,18 @@ abstract class Models { val ddef = tree.asInstanceOf[DefDef]; if (ddef.mods.isAccessor && ddef.symbol != null) { val sym = ddef.symbol.accessed; - val ret = for (val member <- members; member.symbol == sym) yield member; + val ret = for (val member <- members; member.symbol == sym) yield { + member; + } if (ret.isEmpty) null; else ret.head; } else tree; } else super.member(tree, members); + def sym = tree0.symbol; if (tree0 == null || sym.pos == Position.NOPOS) null; + else if (!acceptPrivate && + tree0.isInstanceOf[ValOrDefDef] && tree0.asInstanceOf[ValOrDefDef].mods.isPrivate) null; else tree0; } @@ -314,11 +338,10 @@ abstract class Models { case pdef : PackageDef => update0(pdef.stats); case _ => } + override def add(from : Composite, model : HasTree) : Unit = if (listener != null) { listener.add(from, model); } override def remove(from : Composite, model : HasTree) : Unit = if (listener != null) { listener.remove(from, model); } - private val foo = 10; - override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[Import]; } diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala index c8081a3a7b..e59e5b61f0 100644 --- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala +++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala @@ -231,7 +231,7 @@ class SemanticTokens(val compiler: Global) { try { //TPT=scala.Iterator[DocGenerator.this.compiler0.CompilationUnit] 260 class scala.tools.nsc.ast.Trees$TypeTree scala.Iterator[DocGenerator.this.compiler0.CompilationUnit] class scala.tools.nsc.symtab.Types$$anon$5 if (tree.tpt == null || tree.tpt.tpe == null) { - System.err.println("BAD: " + tree.tpt + " in " + tree); + //System.err.println("BAD: " + tree.tpt + " in " + tree); } else { //System.err.println("TPT=" + tree.tpt + " " + tree.tpt.pos + " " + tree.tpt.getClass() + " " + tree.tpt.tpe + " " + tree.tpt.tpe.getClass() + " " + tree.tpt.tpe.getClass().getSuperclass()); build(tree.tpt); diff --git a/src/compiler/scala/tools/nsc/util/NameTransformer.scala b/src/compiler/scala/tools/nsc/util/NameTransformer.scala index 5fe825eb5e..ddf98f33f0 100644 --- a/src/compiler/scala/tools/nsc/util/NameTransformer.scala +++ b/src/compiler/scala/tools/nsc/util/NameTransformer.scala @@ -61,8 +61,10 @@ object NameTransformer { } /** Replace $op_name by corresponding operator symbol */ - def decode(name: String): String = { + def decode(name0: String): String = { //System.out.println("decode: " + name);//DEBUG + val name = if (name0.endsWith("<init>")) name0.substring(0, name0.length() - ("<init>").length()) + "this"; + else name0; var buf: StringBuffer = null; val len = name.length(); var i = 0; |