summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcremet <cremet@epfl.ch>2003-07-30 08:27:43 +0000
committercremet <cremet@epfl.ch>2003-07-30 08:27:43 +0000
commit90b4108f4586d850a63f40ce2624527a7a270b97 (patch)
treef9f5d7918399752dd4a41dc366fb9054f6a40881
parent3016ae3a598a964690e12ccd2b1de2e8f7cd7a63 (diff)
downloadscala-90b4108f4586d850a63f40ce2624527a7a270b97.tar.gz
scala-90b4108f4586d850a63f40ce2624527a7a270b97.tar.bz2
scala-90b4108f4586d850a63f40ce2624527a7a270b97.zip
Added:
- collecting of documentation comments. - options for scaladoc - a class to load a documentation module.
-rw-r--r--config/list/compiler.lst1
-rw-r--r--sources/scalac/CompilerCommand.java15
-rw-r--r--sources/scalac/DocModule.java100
-rw-r--r--sources/scalac/Global.java22
-rw-r--r--sources/scalac/ast/parser/Parser.java54
-rw-r--r--sources/scalac/ast/parser/Scanner.java31
-rw-r--r--sources/scalac/typechecker/Analyzer.java7
-rw-r--r--sources/scalac/typechecker/DeSugarize.java31
8 files changed, 233 insertions, 28 deletions
diff --git a/config/list/compiler.lst b/config/list/compiler.lst
index 29a15f09a7..75c0fdfcee 100644
--- a/config/list/compiler.lst
+++ b/config/list/compiler.lst
@@ -11,6 +11,7 @@ Phase.java
PhaseDescriptor.java
PhaseRepository.java
Unit.java
+DocModule.java
ast/parser/PatternNormalizer.java
ast/parser/Parser.java
diff --git a/sources/scalac/CompilerCommand.java b/sources/scalac/CompilerCommand.java
index 94f04963e7..5b87d72b46 100644
--- a/sources/scalac/CompilerCommand.java
+++ b/sources/scalac/CompilerCommand.java
@@ -56,6 +56,9 @@ public class CompilerCommand extends CommandParser {
public final ChoiceOptionParser printer;
public final StringOptionParser printfile;
public final PhaseSetOptionParser graph;
+ public final BooleanOptionParser doc;
+ public final StringOptionParser docmodule;
+ public final StringOptionParser docmodulePath;
public final PhaseSetOptionParser stop;
public final PhaseSetOptionParser log;
public final VersionOptionParser version;
@@ -170,6 +173,18 @@ public class CompilerCommand extends CommandParser {
"graph", "Graph the program after <phases> (see below)",
phases.phases, PhaseDescriptor.GRAPH),
+ this.doc = new BooleanOptionParser(this,
+ "doc", "Generate documentation",
+ false),
+
+ this.docmodule = new StringOptionParser(this,
+ "docmodule", "Specify module used by scaladoc",
+ "class", "scaladoc.StandardDocModule"),
+
+ this.docmodulePath = new StringOptionParser(this,
+ "docmodulepath", "Specify where to find doc module class files",
+ "path", ClassPath.CLASS_PATH),
+
this.stop = new PhaseSetOptionParser(this,
"stop", "Stop after first phase in <phases> (see below)",
phases.phases, PhaseDescriptor.STOP),
diff --git a/sources/scalac/DocModule.java b/sources/scalac/DocModule.java
new file mode 100644
index 0000000000..cad5c1f1ab
--- /dev/null
+++ b/sources/scalac/DocModule.java
@@ -0,0 +1,100 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+package scalac;
+
+import scalac.Global;
+import scalac.util.Debug;
+import scalac.util.Reporter;
+import ch.epfl.lamp.util.Position;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.List;
+import java.util.LinkedList;
+import java.lang.reflect.Method;
+
+/**
+ * This class is used to dynamically load a documentation module.
+ */
+public class DocModule {
+
+ /** Name of the method to be called (convention).
+ */
+ protected static final String METHOD_NAME = "apply";
+
+ /** Complete the given path with standard class paths.
+ */
+ public static String completePath(String path) {
+ String completePath = path;
+ String path1 = System.getProperty("env.class.path");
+ String path2 = System.getProperty("java.class.path");
+ if (path1 != null)
+ completePath += File.pathSeparator + path1;
+ if (path2 != null)
+ completePath += File.pathSeparator + path2;
+ return completePath;
+ }
+
+ /** Get class loader from a given path.
+ */
+ public static ClassLoader getClassLoader(String path) {
+ List urlList = new LinkedList();
+ StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
+ try {
+ while (st.hasMoreTokens())
+ urlList.add(new File(st.nextToken()).toURI().toURL());
+ } catch(java.net.MalformedURLException e) {
+ throw Debug.abort(e);
+ }
+ URL[] urls = (URL[]) urlList.toArray(new URL[urlList.size()]);
+ return new URLClassLoader(urls);
+ }
+
+ /** Get a class from its name.
+ */
+ public static Class getClass(String className, ClassLoader classLoader) {
+ Class cls = null;
+ try {
+ cls = classLoader.loadClass(className);
+ } catch (ClassNotFoundException exc) {
+ throw Debug.abort("Class not found", className);
+ }
+ return cls;
+ }
+
+ /** Get the method
+ */
+ public static Method getMethod(String methodName, Class cls) {
+ Method meth = null;
+ try {
+ meth = cls.getMethod(methodName,
+ new Class[] { Class.forName("scalac.Global") });
+ } catch (Exception e) {
+ throw Debug.abort(e);
+ }
+ return meth;
+ }
+
+ public static void apply(Global global) {
+ // complete path
+ String path = completePath(global.docmodulePath);
+ // class loader
+ ClassLoader classLoader = getClassLoader(global.docmodulePath);
+ // module class
+ Class cls = getClass(global.docmodule, classLoader);
+ // method
+ Method meth = getMethod(METHOD_NAME, cls);
+ // call method
+ Thread.currentThread().setContextClassLoader(classLoader);
+ try {
+ meth.invoke(null, new Object[] { global });
+ } catch(Exception e) {
+ throw Debug.abort(e);
+ }
+ }
+}
diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java
index ad0eed1eb7..b5ef83b8ab 100644
--- a/sources/scalac/Global.java
+++ b/sources/scalac/Global.java
@@ -86,6 +86,20 @@ public class Global {
public OutputStream printStream;
public final TreePrinter debugPrinter;
+ /** documentation comments of trees
+ */
+ public final Map/*<Tree, String>*/ mapTreeComment = new HashMap();
+
+ /** documentation comments of symbols
+ */
+ public final Map/*<Symbol, String>*/ mapSymbolComment = new HashMap();
+
+ /** scaladoc option (with docmodule and docmodulepath)
+ */
+ public final boolean doc;
+ public final String docmodule;
+ public final String docmodulePath;
+
/** The set of currenttly compiled top-level symbols
*/
public HashMap/*<Symbol,Sourcefile>*/ compiledNow = new HashMap();
@@ -174,6 +188,9 @@ public class Global {
else
this.printer = new HTMLTreePrinter(printStream);
this.debugPrinter = new TextTreePrinter(System.err, true);
+ this.doc = args.doc.value;
+ this.docmodule = args.docmodule.value;
+ this.docmodulePath = args.docmodulePath.value;
this.freshNameCreator = new FreshNameCreator();
this.make = new DefaultTreeFactory();
this.currentPhase = PhaseDescriptor.INITIAL;
@@ -288,6 +305,11 @@ public class Global {
}
if (currentPhase == PHASE.PARSER) fix1();
if (currentPhase == PHASE.ANALYZER) fix2();
+ if (currentPhase == PHASE.ANALYZER && doc) {
+ DocModule.apply(this);
+ operation("stopped after phase " + currentPhase.name());
+ break;
+ }
}
if (reporter.errors() != 0) {
imports.clear();
diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java
index d5b3522367..00670ab8fc 100644
--- a/sources/scalac/ast/parser/Parser.java
+++ b/sources/scalac/ast/parser/Parser.java
@@ -40,6 +40,7 @@ public class Parser implements Tokens {
s = new Scanner(unit);
make = unit.global.make;
pN = new PatternNormalizer( unit );
+ mapTreeComment = unit.global.mapTreeComment;
}
/** this is the general parse method
@@ -161,6 +162,38 @@ public class Parser implements Tokens {
}
}
+/////// COMMENT COLLECTION ///////////////////////////////////////////////////
+
+ /** keep the comments associated with a given tree
+ */
+ protected Map mapTreeComment;
+
+ /** stack of comments
+ */
+ protected final Stack commentStack = new Stack();
+
+ /** positive if we are inside a block
+ */
+ protected int local = 0;
+
+ /** push last encountered comment and reset the buffer
+ */
+ protected void pushComment() {
+ if (local == 0) {
+ commentStack.push(s.docBuffer == null ? null : s.docBuffer.toString());
+ s.docBuffer = null;
+ }
+ }
+
+ /** pop a comment from the stack and associate it with the given tree
+ */
+ protected Tree popComment(Tree tree) {
+ if (local == 0)
+ if (!commentStack.empty())
+ mapTreeComment.put(tree, (String) commentStack.pop());
+ return tree;
+ }
+
/////// TREE CONSTRUCTION ////////////////////////////////////////////////////
/** Name supply
@@ -995,6 +1028,7 @@ public class Parser implements Tokens {
* | `{' Block `}'
*/
Tree blockExpr() {
+ local++;
Tree res;
int pos = accept(LBRACE);
if (s.token == CASE) {
@@ -1008,6 +1042,7 @@ public class Parser implements Tokens {
res = block(pos);
}
accept(RBRACE);
+ local--;
return res;
}
@@ -1265,6 +1300,7 @@ public class Parser implements Tokens {
* | abstract
*/
int modifiers() {
+ pushComment();
int mods = 0;
while (true) {
int mod;
@@ -1551,25 +1587,25 @@ public class Parser implements Tokens {
case VAL:
do {
s.nextToken();
- ts.append(patDefOrDcl(mods));
+ ts.append(popComment(patDefOrDcl(mods)));
} while (s.token == COMMA);
return ts.toArray();
case VAR:
do {
s.nextToken();
- ts.append(varDefOrDcl(mods));
+ ts.append(popComment(varDefOrDcl(mods)));
} while (s.token == COMMA);
return ts.toArray();
case DEF:
do {
s.nextToken();
- ts.append(funDefOrDcl(mods));
+ ts.append(popComment(funDefOrDcl(mods)));
} while (s.token == COMMA);
return ts.toArray();
case TYPE:
do {
s.nextToken();
- ts.append(typeDefOrDcl(mods));
+ ts.append(popComment(typeDefOrDcl(mods)));
} while (s.token == COMMA);
return ts.toArray();
default:
@@ -1725,11 +1761,11 @@ public class Parser implements Tokens {
ValDef[][] params = paramClauseOpt();
TreeList result = new TreeList();
result.append(
- make.ClassDef(pos, mods, clazzname, tparams, params,
- simpleTypedOpt(), classTemplate()));
+ popComment(make.ClassDef(pos, mods, clazzname, tparams, params,
+ simpleTypedOpt(), classTemplate())));
while (s.token == CONSTR) {
s.nextToken();
- result.append(constrDef(mods, clazzname, tparams));
+ result.append(popComment(constrDef(mods, clazzname, tparams)));
}
return result.toArray();
}
@@ -1737,8 +1773,8 @@ public class Parser implements Tokens {
/** ObjectDef ::= Id [`:' SimpleType] ClassTemplate
*/
Tree objectDef(int mods) {
- return make.ModuleDef(
- s.pos, mods, ident(), simpleTypedOpt(), classTemplate());
+ return popComment(make.ModuleDef(
+ s.pos, mods, ident(), simpleTypedOpt(), classTemplate()));
}
/** ClassTemplate ::= [`extends' Constr] {`with' Constr} [TemplateBody]
diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java
index bc153c869f..c747fc1bcc 100644
--- a/sources/scalac/ast/parser/Scanner.java
+++ b/sources/scalac/ast/parser/Scanner.java
@@ -23,6 +23,16 @@ import scalac.util.Name;
*/
public class Scanner extends TokenData {
+ /** buffer for the documentation comment
+ */
+ protected StringBuffer docBuffer = null;
+
+ /** add the given character to the documentation buffer
+ */
+ protected void addCharToDoc(byte ch) {
+ if (docBuffer != null) docBuffer.append((char) ch);
+ }
+
/** layout & character constants
*/
public int tabinc = 8;
@@ -342,38 +352,43 @@ public class Scanner extends TokenData {
} while ((ch != CR) && (ch != LF) && (ch != SU));
return true;
} else if (ch == '*') {
+ docBuffer = null;
int openComments = 1;
+ nextch();
+ if (ch == '*') {
+ docBuffer = new StringBuffer("/**");
+ }
while (openComments > 0) {
do {
do {
if (ch == CR) {
cline++;
ccol = 0;
- nextch();
+ nextch(); addCharToDoc(ch);
if (ch == LF) {
ccol = 0;
- nextch();
+ nextch(); addCharToDoc(ch);
}
} else if (ch == LF) {
cline++;
ccol = 0;
- nextch();
+ nextch(); addCharToDoc(ch);
}
else if (ch == '\t') {
ccol = ((ccol - 1) / tabinc * tabinc) + tabinc;
- nextch();
+ nextch(); addCharToDoc(ch);
} else if (ch == '/') {
- nextch();
+ nextch(); addCharToDoc(ch);
if (ch == '*') {
- nextch();
+ nextch(); addCharToDoc(ch);
openComments++;
}
} else {
- nextch();
+ nextch(); addCharToDoc(ch);
}
} while ((ch != '*') && (ch != SU));
while (ch == '*') {
- nextch();
+ nextch(); addCharToDoc(ch);
}
} while (ch != '/' && ch != SU);
if (ch == '/') {
diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java
index bcb7dcb7b7..79b1a0900e 100644
--- a/sources/scalac/typechecker/Analyzer.java
+++ b/sources/scalac/typechecker/Analyzer.java
@@ -731,7 +731,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, _, Tree.Template templ):
ClassSymbol clazz = new ClassSymbol(tree.pos, name, owner, mods);
if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz);
-
enterSym(tree, clazz.constructor());
if ((mods & CASE) != 0) {
/* todo: remove
@@ -793,6 +792,12 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
sym.flags |= FINAL;
sym = enterInScope(sym);
tree.setSymbol(sym);
+
+ // set the comment associated with a symbol
+ String comment = (String) global.mapTreeComment.get(tree);
+ if (comment != null)
+ global.mapSymbolComment.put(sym, comment);
+
return sym;
}
diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java
index b8539a9fa4..e5634390e4 100644
--- a/sources/scalac/typechecker/DeSugarize.java
+++ b/sources/scalac/typechecker/DeSugarize.java
@@ -394,6 +394,17 @@ public class DeSugarize implements Kinds, Modifiers {
}
}
+ /** make a set of trees share the same documentation comment as a
+ * given tree (used for pattern and val definitions)
+ */
+ Tree[] shareComment(Tree[] trees, Tree tree) {
+ String comment = (String) global.mapTreeComment.get(tree);
+ if (comment != null)
+ for(int i = 0; i < trees.length; i++)
+ global.mapTreeComment.put(trees[i], comment);
+ return trees;
+ }
+
/** expand pattern definitions and variable definitions in templates.
*/
public Tree[] Statements(Tree[] stats, boolean isLocal) {
@@ -458,13 +469,13 @@ public class DeSugarize implements Kinds, Modifiers {
case PatDef(int mods, Ident(Name name), Tree rhs):
// val x = e ==> val x = e
- return new Tree[]{
- make.ValDef(tree.pos, mods, name, Tree.Empty, rhs)};
+ return shareComment(new Tree[]{
+ make.ValDef(tree.pos, mods, name, Tree.Empty, rhs)}, tree);
case PatDef(int mods, Typed(Ident(Name name), Tree type), Tree rhs):
// val x: T = e ==> val x: T = e
- return new Tree[]{
- make.ValDef(tree.pos, mods, name, type, rhs)};
+ return shareComment(new Tree[]{
+ make.ValDef(tree.pos, mods, name, type, rhs)}, tree);
case PatDef(int mods, Tree pat, Tree rhs):
int pos = tree.pos;
@@ -494,7 +505,7 @@ public class DeSugarize implements Kinds, Modifiers {
// val x_1 = e.match (case p => x_1)
Tree valdef = make.ValDef(pos, mods, vars[0], Tree.Empty, match);
print(pat, "patdef", valdef);
- return new Tree[]{valdef};
+ return shareComment(new Tree[]{valdef}, tree);
} else {
// t$
Name var = getvar();
@@ -510,7 +521,7 @@ public class DeSugarize implements Kinds, Modifiers {
make.Select(pos, make.Ident(pos, var), tupleSelectorName(i + 1)));
}
print(pat, "patdef", new Block(res));//debug
- return res;
+ return shareComment(res, tree);
}
default:
throw new ApplicationError("pattern definition expected", tree);
@@ -533,8 +544,8 @@ public class DeSugarize implements Kinds, Modifiers {
((mods & DEFERRED) != 0) ? Tree.Empty
: make.Ident(tree.pos, valname));
if ((mods1 & MUTABLE) == 0) {
- if ((mods1 & DEFERRED) != 0) return new Tree[]{getter};
- else return new Tree[]{valdef1, getter};
+ if ((mods1 & DEFERRED) != 0) return shareComment(new Tree[]{getter}, tree);
+ else return shareComment(new Tree[]{valdef1, getter}, tree);
} else {
Tree setter = make.DefDef(
tree.pos, mods1, setterName(name),
@@ -548,8 +559,8 @@ public class DeSugarize implements Kinds, Modifiers {
tree.pos,
make.Ident(tree.pos, valname),
make.Ident(tree.pos, parameterName(0))));
- if ((mods1 & DEFERRED) != 0) return new Tree[]{getter, setter};
- else return new Tree[]{valdef1, getter, setter};
+ if ((mods1 & DEFERRED) != 0) return shareComment(new Tree[]{getter, setter}, tree);
+ else return shareComment(new Tree[]{valdef1, getter, setter}, tree);
}
default:
throw new ApplicationError();