package x10doc.doc; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.MemberDoc; import com.sun.javadoc.PackageDoc; import com.sun.javadoc.SeeTag; import com.sun.javadoc.Tag; public class X10SeeTag extends X10Tag implements SeeTag { String label, itemName; X10RootDoc rootDoc; PackageDoc pkgDoc; X10ClassDoc classDoc; MemberDoc memberDoc; public X10SeeTag(String name, String label, String text, X10Doc holder) { super(name, text, holder); rootDoc = X10RootDoc.getRootDoc(); // processText(label); // pkgDoc = null; // classDoc = null; // memberDoc = null; this.label = itemName = label; // int i = text.indexOf(tag); // assert (i > 0) : "X10SeeTag constructor: " + text + "does not contain " + tag; // BreakIterator b = BreakIterator.getWordInstance(); // String bText = text.substring(i+5, text.length()).trim(); // b.setText(bText); // int start = b.first(), end = b.next(); // this.itemName = bText.substring(start, end).trim(); // start = end; // end = bText.indexOf('}', start); // if (start <= end) { // this.label = bText.substring(start, end).trim(); // } } void processText() { String text = label; int index = text.indexOf("#"); String classname = null; String member = null; if (index == -1) { classname = text; } else { classname = text.substring(0, index); if(classname.endsWith("]")) { classname = classname.substring(0, classname.indexOf("[")); } member = text.substring(index + 1); } if (classname.equals("")) { classname = X10RootDoc.getContainingClass(holder); } classDoc = (X10ClassDoc) rootDoc.classNamed(classname); if (classDoc == null) { classDoc = rootDoc.findClass(holder, classname); } if (classDoc == null) { String container = X10RootDoc.getContainingClass(holder); if (container != null) classname = container; classDoc = (X10ClassDoc) rootDoc.classNamed(classname); member = text; } else { classname = classDoc.qualifiedName(); } if (member != null && classDoc != null) { memberDoc = classDoc.getMemberDoc(member); } index = classname.lastIndexOf("."); if (index != -1) { String pkgname = classname.substring(0, index); pkgDoc = rootDoc.packageNamed(pkgname); } if(label.startsWith("#")) { label = label.substring(1); } } public void processLinkTag(String text) { // Pattern p = Pattern.compile("\\{\\s*(@[^\\s]*)\\s*(([^\\s]*)\\.)?(([^\\s\\.#\\(]*)#)?([^\\s\\(]*)(\\([^\\)]*\\))?\\s*([^\\}]*)\\}"); Pattern p = Pattern.compile("\\{\\s*(@[^\\s]+)\\s*(([^\\s]+)\\.)?(([^\\s\\.#\\(]*)#)?([^\\s\\(]+)(\\([^\\)]*\\))?\\s*([^\\}]*)\\}"); // explanation of pattern: 3 parts of pattern for 3 entities of tag // {@---- package.class#member(...) label?} // ---------|----------------------------|------- // part1 part2 part3 // [part1] \\{\\s*(@[^\\s]*)\\s* // [part2] (([^\\s]+)\\.)?(([^\\s\\.#\\(]*)#)?([^\\s\\(]+)(\\([^\\)]*\\))?\\s* // [further split into subparts and explained] // (([^\\s]+)\\.)?: any seq of chars other than whitespace (may // include period) followed by a period, 0 or 1 occurrence of such a // seq; contains groups 2 and 3; 3 might be the package name // (([^\\s\\.#\\(]*)#)? : any seq of chars other than whitespace, // period, #, and (, followed by #, 0 or 1 occurrence of such a seq; // contains groups 4 and 5; 5 might be the class name // ([^\\s\\(]+): any seq of chars other than whitespace and (; // contains group 6; notice that such a seq must occur in the input // string but because of the "*" this pattern matches the empty // string also; might be the class or the member name // (\\([^\\)]*\\))?: seq containing '(', followed by any string of // chars other than ')', followed by ')', 0 or 1 occurrence of such a // seq; contains group 7; m.group(7) is the list of param types // [part3] ([^\\}]*)\\} // ([^\\}]*)\\}: any seq of chars other than '}', followed by '}'; contains group 8; label = m.group(8) Matcher m = p.matcher(text); String pkgName, className, memberName; String g3, g4, g5, g6, g7, g8; X10ClassDoc cd; if (m.find()) { g3 = m.group(3); // (([^\\s]+)\\.)? contains 2 and 3 g4 = m.group(4); // (([^\\s\\.#\\(]*)#)? contains 4 and 5 g5 = m.group(5); // (([^\\s\\.#\\(]*)#)? contains 4 and 5 g6 = m.group(6); // ([^\\s\\(]+) contains 6 g7 = m.group(7); // (\\([^\\)]*\\))? contains 7 g8 = m.group(8); // ([^\\}]*)\\} contains 8 this.label = g8.trim(); System.out.println("m.group() = \"" + m.group() + "\""); System.out.println("tag = m.group(1) = \"" + m.group(1) + "\""); System.out.println("m.group(2) = \"" + m.group(2) + "\""); System.out.println("m.group(3) = \"" + g3 + "\""); System.out.println("m.group(4) = \"" + g4 + "\""); System.out.println("m.group(5) = \"" + g5 + "\""); System.out.println("m.group(6) = \"" + g6 + "\""); System.out.println("m.group(7) = \"" + g7 + "\""); System.out.println("label = m.group(8).trim() = \"" + this.label + "\""); if (g4 != null) { // text contains #; so, item is a class member (field, constructor, method); note // that class.nestedClass#member is not allowed, although class.nestedClass is if (g3 != null) { // g3 is the package name className = g3 + "." + g5; // if g3 is non-null, then g5 must be non-null cd = (X10ClassDoc) rootDoc.classNamed(className); } else if (g5 != null) { // null package name, and non-null class name pkgName = rootDoc.holderClass(holder).containingPackage().name(); className = pkgName + "." + g5; // g5 is a class in the holding class's package cd = (X10ClassDoc) rootDoc.classNamed(className); } else { // null package name, null class name cd = rootDoc.holderClass(holder); // g6 is a member of the current class } if (g7 == null) { // null list of parameters memberDoc = cd.getField(g6); } else { // TODO: needs to be modified to get the correct signature with fully qualified types, and // remove arg names if present memberDoc = cd.getConstructor(g6 + g7); if (memberDoc == null) { memberDoc = cd.getMethod(g6 + g7); } } } else { // item is a package, class, or nested class String pgmElem = ((g3 == null) ? "" : g3) + ((g5 == null) ? "" : g5); pkgDoc = (X10PackageDoc) rootDoc.packageNamed(pgmElem); if (pkgDoc == null) { classDoc = (X10ClassDoc) rootDoc.classNamed(pgmElem); } } // if (listParams != null || m.group(4).endsWith("#")) { // memberName = m.group(6); // assert(className != null && memberName != null) : // "processLinkTag: unable to find class/method name for tag."; // if (packageName != null) { // cd = (X10ClassDoc) rootDoc.classNamed(packageName + "." + className); // } // else if (className != null) { // } // else { // cd = (X10ClassDoc) holder; // } // // lookup cd for method/constructor/field // } } } @Override public Tag[] firstSentenceTags() { return new Tag[0]; } @Override public Tag[] inlineTags() { X10Tag[] result = new X10Tag[1]; result[0] = new X10Tag("Text", text, holder); return result; } public String label() { if(classDoc == null) { processText(); } return label; } public ClassDoc referencedClass() { return classDoc; } public String referencedClassName() { if(classDoc != null) { return classDoc.qualifiedName(); } if(pkgDoc != null) { return pkgDoc.name(); } return null; } public MemberDoc referencedMember() { return memberDoc; } public String referencedMemberName() { // return itemName; return ((memberDoc == null) ? null : memberDoc.qualifiedName()); } public PackageDoc referencedPackage() { if(classDoc != null || memberDoc != null) { return null; } return pkgDoc; } }