package x10doc.visit; import java.io.IOException; import java.util.Stack; import lpg.runtime.IToken; import polyglot.ast.ClassMember; import polyglot.ast.Node; import polyglot.ast.SourceFile_c; import polyglot.ast.TopLevelDecl; import polyglot.frontend.FileSource; import polyglot.frontend.Job; import polyglot.types.ClassDef.Kind; import polyglot.types.FieldDef; import polyglot.types.Flags; import polyglot.types.Name; import polyglot.types.QName; import polyglot.types.Ref_c; import polyglot.types.SemanticException; import polyglot.types.TypeSystem; import polyglot.util.SilentErrorQueue; import x10.ast.PropertyDecl; import x10.ast.PropertyDecl_c; import x10.ast.TypeDecl_c; import x10.ast.X10ClassDecl_c; import x10.ast.X10ConstructorDecl_c; import x10.ast.X10FieldDecl_c; import x10.ast.X10MethodDecl_c; import x10.ast.X10SourceFile_c; import x10.extension.X10Ext; import x10.parser.X10SemanticRules; import x10.types.TypeDef; import x10.types.X10ClassDef; import x10.types.X10ConstructorDef; import x10.types.X10FieldDef; import x10.types.X10MethodDef; import x10.visit.X10DelegatingVisitor; import x10doc.ExtensionInfo; import x10doc.doc.X10ClassDoc; import x10doc.doc.X10PackageDoc; import x10doc.doc.X10RootDoc; public class X10DocGenerator extends X10DelegatingVisitor { private final Job job; private X10SemanticRules parser; private X10RootDoc rootDoc; private Stack<X10ClassDoc> stack; private X10SourceFile_c source; // stack of X10ClassDoc objects created as X10ClassDecl_c objects are visited; the // X10ClassDecl_c objects visited included top level class declarations and inner classes; // when a Doc object is created for a class member, it is added as a member of the top // X10ClassDoc object of stack; private static final String PACKAGE_DUMMY_CLASS_NAME= "___TopLevelTypeDefs"; public X10DocGenerator(Job job) { this.job = job; } @Override public void visit(Node n) { assert false : "visit: Unexpected node type " + n.getClass(); } @Override public void visit(SourceFile_c n) { assert (job.source() instanceof FileSource); FileSource source = (FileSource) job.source(); this.source = (X10SourceFile_c)n; try { this.parser = (X10SemanticRules) job.extensionInfo().parser(source.open(), source, new SilentErrorQueue(0, "Ignored")); } catch (IOException e) { assert false : "Cannot reparse file " + source; } // List<TopLevelDecl> decls = n.decls(); // X10ClassDoc[] classes = new X10ClassDoc[decls.size()]; ExtensionInfo extInfo = (ExtensionInfo)job.extensionInfo(); this.rootDoc = X10RootDoc.getRootDoc(extInfo.getOptions().output_directory.getPath(), extInfo.getOptions().doc_access_modifier); this.stack = new Stack<X10ClassDoc>(); for (TopLevelDecl td: n.decls()) { // System.out.println("in visit(SourceFile_c): topleveldecl.getClass() = " + td.getClass()); visitAppropriate(td); } ((ExtensionInfo) job.extensionInfo()).setRoot(this.rootDoc); // rootDoc.printStats(); this.parser = null; } private String getDocComments(Node n) { String s = ((X10Ext) n.ext()).comment(); if (s != null) return s; return printDocComments(n.position().offset()); } @Override public void visit(X10ClassDecl_c n) { String comments = getDocComments(n); /* System.out.println("visit(X10ClassDecl_c): Extracted comment text follows."); System.out.println(X10Doc.rawCommentToText(comments)); */ // the following obtains an x10doc-specific context // X10DocData data = ((X10DocContext) tr.context()).getData(); // if (n.flags().flags().isPrivate()) // return; /* System.out.print("Class: " + n.name() + "["); for (ParameterType p: ((X10ClassDef) n.classDef()).typeParameters()) { // param name, bounds System.out.print("<" + p.name().toString() + "," + p.def().get() + ">, "); p.toType(); } // TypeParamNode x; System.out.println("]"); System.out.print(" Properties: "); for (PropertyDecl p: n.properties()) { System.out.print(p.name() + ", "); } System.out.println(); System.out.print(" Interfaces: "); for (TypeNode i: n.interfaces()) { System.out.print(i.nameString() + ", "); X10ClassDef iClassDef = (X10ClassDef) i.type().toClass().def(); } System.out.println(); */ X10ClassDoc containingClass = (stack.isEmpty() ? null : stack.peek()); X10ClassDef classDef = (X10ClassDef) n.classDef(); // System.out.println("ClassDef.fullname() = " + classDef.fullName()); // boolean isIncluded = ((job.extensionInfo().scheduler().commandLineJobs().contains(job) || // (containingClass != null && containingClass.isIncluded()))); // the class is included in the "specified set" if it is specified on the command line // or it is an inner class of an included class X10ClassDoc cd = rootDoc.getSpecCLass(classDef, containingClass, comments); cd.setSource(source); // all classes, including inner classes are added to rootDoc // for (TypeNode i: n.interfaces()) { // X10ClassDef intClassDef = (X10ClassDef) i.type().toClass().def(); // X10ClassDoc intClassDoc = rootDoc.createRecClassDoc(intClassDef); // cd.addInterface(intClassDoc); // } // X10PackageDoc containingPackage = rootDoc.getPackage(classDef.package_()); // X10ClassDoc cd = new X10ClassDoc(classDef, containingClass, rootDoc, comments); // cd.setPackage(containingPackage); // containingPackage.addClass(cd); // cd.setIncluded((job.extensionInfo().scheduler().commandLineJobs().contains(job) || // (containingClass != null && containingClass.isIncluded()))); stack.push(cd); for (PropertyDecl p: n.properties()) { // properties are not included in n.body().member() visitAppropriate(p); } for (ClassMember cm: n.body().members()) { visitAppropriate(cm); } cd = stack.pop(); // rootDoc.addClass(cd); // inner classes are also added to rootDoc if (containingClass != null) { containingClass.addInnerClass(cd); } } @Override public void visit(PropertyDecl_c n) { String comments = "/** Property. */"; FieldDef fd = n.fieldDef(); X10ClassDoc cd = stack.peek(); cd.updateField((X10FieldDef) fd, comments); } @Override public void visit(X10FieldDecl_c n) { String comments = getDocComments(n); FieldDef fd = n.fieldDef(); /* if (!n.flags().flags().isPrivate()) { System.out.println(" Field: " + n.flags().flags() + " " + n.type().toString() + " " + n.name()); } System.out.println(" fd.toString() = " + fd); System.out.println(" fd = n.fieldDef(); fd.name().toString() = " + fd.name()); System.out.println(" fd.type().toString() = " + fd.type().toString()); System.out.println(" fd.type().get().isArray() = " + fd.type().get().isArray()); if (fd.type().get().isArray()) { System.out.println(" fd.type().get().toArray().dims() = " + fd.type().get().toArray().dims()); } */ X10ClassDoc cd = stack.peek(); // cd.addField(new X10FieldDoc((X10FieldDef) fd, cd, comments)); cd.updateField((X10FieldDef) fd, comments); } @Override public void visit(X10ConstructorDecl_c n) { String comments = getDocComments(n); /* System.out.print(" Constructor: " + n.returnType().nameString() + " " + n.name() + "("); boolean first = true; for (Formal f: n.formals()) { if (first) { System.out.print(f.type().nameString() + " " + f.name()); first = false; } else { System.out.print(", " + f.type().nameString() + " " + f.name()); } } System.out.println(")"); */ X10ClassDoc cd = stack.peek(); // cd.addConstructor(new X10ConstructorDoc(((X10ConstructorDef) n.constructorDef()), cd, comments)); // X10ConstructorDoc constrDoc = new X10ConstructorDoc(((X10ConstructorDef) n.constructorDef()), cd, comments); cd.updateConstructor(((X10ConstructorDef) n.constructorDef()), comments); } @Override public void visit(X10MethodDecl_c n) { String comments = getDocComments(n); /* System.out.print(" Method: " + n.returnType().nameString() + " " + n.name() + "("); boolean first = true; for (Formal f: n.formals()) { if (first) { System.out.print(f.type().nameString() + " " + f.name()); first = false; } else { System.out.print(", " + f.type().nameString() + " " + f.name()); } } System.out.println(")"); */ X10ClassDoc cd = stack.peek(); // cd.addMethod(new X10MethodDoc(((X10MethodDef) n.methodDef()), cd, comments)); // X10MethodDoc md = new X10MethodDoc(((X10MethodDef) n.methodDef()), cd, comments); cd.updateMethod(((X10MethodDef) n.methodDef()), comments); } @Override public void visit(TypeDecl_c n) { // System.out.println("visit(TypeDecl_c{" + n + "}: node not handled"); String comments = getDocComments(n); TypeDef def = n.typeDef(); X10ClassDoc xcd = null; if (stack.isEmpty()) { // Find/create the dummy X10ClassDoc for the top-level typedefs/typedecls in this package. // First need to figure out what "this package" is... try { String typeDeclFullName = n.type().qualifierRef().get().toType().fullName().toString(); String packageName = typeDeclFullName.substring(0, typeDeclFullName.lastIndexOf('.')); X10PackageDoc pkgDoc = (X10PackageDoc) rootDoc.packageNamed(packageName); // com.sun.javadoc.ClassDoc[] pkgClasses = pkgDoc.allClasses(); xcd = pkgDoc.classDocForName(PACKAGE_DUMMY_CLASS_NAME); if (xcd == null) { TypeSystem typeSystem= job.extensionInfo().typeSystem(); X10ClassDef x10CDef = (X10ClassDef) typeSystem.createClassDef(); x10CDef.name(Name.make(PACKAGE_DUMMY_CLASS_NAME)); x10CDef.flags(Flags.PUBLIC); x10CDef.kind(Kind.TOP_LEVEL); polyglot.types.Package pkg= typeSystem.packageForName(QName.make(packageName)); x10CDef.setPackage(new Ref_c<polyglot.types.Package>(pkg)); X10ClassDoc packageDummyClassDoc = new X10ClassDoc(x10CDef, null, "/** Top-level typedecls/defs for the package " + packageName + "**/"); xcd = packageDummyClassDoc; xcd.setIncluded(); xcd.setPackage(pkgDoc); pkgDoc.addClass(xcd); rootDoc.addDummyClass(xcd); } } catch (SemanticException e) { e.printStackTrace(System.err); return; } } else { xcd = stack.peek(); } xcd.updateTypeDef(def, comments); } // go through comments preceding a given offset corresponding to a class/method/... // declaration, and print documentation comments String printDocComments(int offset) { String retVal = null; for (IToken t: parser.getIPrsStream().getTokenAtCharacter(offset).getPrecedingAdjuncts()) { String str = t.toString().trim(); if (str.startsWith("/**")) { // System.out.println("adjunct: " + t); retVal = str; } } return retVal; } }