OSDN Git Service

eclair snapshot
[android-x86/build.git] / tools / droiddoc / src / Comment.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 import java.util.regex.Pattern;
18 import java.util.regex.Matcher;
19 import java.util.ArrayList;
20
21 public class Comment
22 {
23     static final Pattern LEADING_WHITESPACE = Pattern.compile(
24                                 "^[ \t\n\r]*(.*)$",
25                                 Pattern.DOTALL);
26
27     static final Pattern TAG_BEGIN = Pattern.compile(
28                                 "[\r\n][\r\n \t]*@",
29                                 Pattern.DOTALL);
30
31     static final Pattern TAG = Pattern.compile(
32                                 "(@[^ \t\r\n]+)[ \t\r\n]+(.*)",
33                                 Pattern.DOTALL);
34
35     static final Pattern INLINE_TAG = Pattern.compile(
36                                 "(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}",
37                                 Pattern.DOTALL);
38
39     static final Pattern FIRST_SENTENCE = Pattern.compile(
40                                 "((.*?)\\.)[ \t\r\n\\<](.*)",
41                                 Pattern.DOTALL);
42
43     private static final String[] KNOWN_TAGS = new String[] {
44             "@author",
45             "@since",
46             "@version",
47             "@deprecated",
48             "@undeprecate",
49             "@docRoot",
50             "@sdkCurrent",
51             "@inheritDoc",
52             "@more",
53             "@code",
54             "@samplecode",
55             "@sample",
56             "@include",
57             "@serial",
58             "@com.intel.drl.spec_ref",
59             "@ar.org.fitc.spec_ref",
60         };
61
62     public Comment(String text, ContainerInfo base, SourcePositionInfo sp)
63     {
64         mText = text;
65         mBase = base;
66         // sp now points to the end of the text, not the beginning!
67         mPosition = SourcePositionInfo.findBeginning(sp, text);
68     }
69
70     private void parseRegex(String text)
71     {
72         Matcher m;
73
74         m = LEADING_WHITESPACE.matcher(text);
75         m.matches();
76         text = m.group(1);
77
78         m = TAG_BEGIN.matcher(text);
79
80         int start = 0;
81         int end = 0;
82         while (m.find()) {
83             end = m.start();
84
85             tag(text, start, end);
86
87             start = m.end()-1; // -1 is the @
88         }
89         end = text.length();
90         tag(text, start, end);
91     }
92
93     private void tag(String text, int start, int end)
94     {
95         SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
96
97         if (start >= 0 && end > 0 && (end-start) > 0) {
98             text = text.substring(start, end);
99
100             Matcher m = TAG.matcher(text);
101             if (m.matches()) {
102                 // out of line tag
103                 tag(m.group(1), m.group(2), false, pos);
104             } else {
105                 // look for inline tags
106                 m = INLINE_TAG.matcher(text);
107                 start = 0;
108                 while (m.find()) {
109                     String str = m.group(1);
110                     String tagname = m.group(2);
111                     String tagvalue = m.group(3);
112                     tag(null, m.group(1), true, pos);
113                     tag(tagname, tagvalue, true, pos);
114                     start = m.end();
115                 }
116                 int len = text.length();
117                 if (start != len) {
118                     tag(null, text.substring(start), true, pos);
119                 }
120             }
121         }
122     }
123
124     private void tag(String name, String text, boolean isInline, SourcePositionInfo pos)
125     {
126         /*
127         String s = isInline ? "inline" : "outofline";
128         System.out.println("---> " + s
129                 + " name=[" + name + "] text=[" + text + "]");
130         */
131         if (name == null) {
132             mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
133         }
134         else if (name.equals("@param")) {
135             mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
136         }
137         else if (name.equals("@see")) {
138             mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
139         }
140         else if (name.equals("@link") || name.equals("@linkplain")) {
141             mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
142         }
143         else if (name.equals("@throws") || name.equals("@exception")) {
144             mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
145         }
146         else if (name.equals("@return")) {
147             mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
148         }
149         else if (name.equals("@deprecated")) {
150             if (text.length() == 0) {
151                 Errors.error(Errors.MISSING_COMMENT, pos,
152                         "@deprecated tag with no explanatory comment");
153                 text = "No replacement.";
154             }
155             mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
156         }
157         else if (name.equals("@literal")) {
158             mInlineTagsList.add(new LiteralTagInfo(name, name, text, pos));
159         }
160         else if (name.equals("@hide") || name.equals("@pending") || name.equals("@doconly")) {
161             // nothing
162         }
163         else if (name.equals("@attr")) {
164             AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
165             mAttrTagsList.add(tag);
166             Comment c = tag.description();
167             if (c != null) {
168                 for (TagInfo t: c.tags()) {
169                     mInlineTagsList.add(t);
170                 }
171             }
172         }
173         else if (name.equals("@undeprecate")) {
174             mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
175         }
176         else if (name.equals("@include") || name.equals("@sample")) {
177             mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
178         }
179         else {
180             boolean known = false;
181             for (String s: KNOWN_TAGS) {
182                 if (s.equals(name)) {
183                     known = true;
184                     break;
185                 }
186             }
187             if (!known) {
188                 Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
189                         "Unknown tag: " + name);
190             }
191             TagInfo t = new TextTagInfo(name, name, text, pos);
192             if (isInline) {
193                 mInlineTagsList.add(t);
194             } else {
195                 mTagsList.add(t);
196             }
197         }
198     }
199
200     private void parseBriefTags()
201     {
202         int N = mInlineTagsList.size();
203
204         // look for "@more" tag, which means that we might go past the first sentence.
205         int more = -1;
206         for (int i=0; i<N; i++) {
207             if (mInlineTagsList.get(i).name().equals("@more")) {
208                 more = i;
209             }
210         }
211           if (more >= 0) {
212             for (int i=0; i<more; i++) {
213                 mBriefTagsList.add(mInlineTagsList.get(i));
214             }
215         } else {
216             for (int i=0; i<N; i++) {
217                 TagInfo t = mInlineTagsList.get(i);
218                 if (t.name().equals("Text")) {
219                     Matcher m = FIRST_SENTENCE.matcher(t.text());
220                     if (m.matches()) {
221                         String text = m.group(1);
222                         TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
223                         mBriefTagsList.add(firstSentenceTag);
224                         break;
225                     }
226                 }
227                 mBriefTagsList.add(t);
228
229             }
230         }
231     }
232
233     public TagInfo[] tags()
234     {
235         init();
236         return mInlineTags;
237     }
238
239     public TagInfo[] tags(String name)
240     {
241         init();
242         ArrayList<TagInfo> results = new ArrayList<TagInfo>();
243         int N = mInlineTagsList.size();
244         for (int i=0; i<N; i++) {
245             TagInfo t = mInlineTagsList.get(i);
246             if (t.name().equals(name)) {
247                 results.add(t);
248             }
249         }
250         return results.toArray(new TagInfo[results.size()]);
251     }
252
253     public ParamTagInfo[] paramTags()
254     {
255         init();
256         return mParamTags;
257     }
258
259     public SeeTagInfo[] seeTags()
260     {
261         init();
262         return mSeeTags;
263     }
264
265     public ThrowsTagInfo[] throwsTags()
266     {
267         init();
268         return mThrowsTags;
269     }
270
271     public TagInfo[] returnTags()
272     {
273         init();
274         return mReturnTags;
275     }
276
277     public TagInfo[] deprecatedTags()
278     {
279         init();
280         return mDeprecatedTags;
281     }
282
283     public TagInfo[] undeprecateTags()
284     {
285         init();
286         return mUndeprecateTags;
287     }
288
289     public AttrTagInfo[] attrTags()
290     {
291         init();
292         return mAttrTags;
293     }
294
295     public TagInfo[] briefTags()
296     {
297         init();
298         return mBriefTags;
299     }
300
301     public boolean isHidden()
302     {
303         if (mHidden >= 0) {
304             return mHidden != 0;
305         } else {
306             if (DroidDoc.checkLevel(DroidDoc.SHOW_HIDDEN)) {
307                 mHidden = 0;
308                 return false;
309             }
310             boolean b = mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0;
311             mHidden = b ? 1 : 0;
312             return b;
313         }
314     }
315
316     public boolean isDocOnly() {
317         if (mDocOnly >= 0) {
318             return mDocOnly != 0;
319         } else {
320             boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
321             mDocOnly = b ? 1 : 0;
322             return b;
323         }
324     }
325
326     private void init()
327     {
328         if (!mInitialized) {
329             initImpl();
330         }
331     }
332
333     private void initImpl()
334     {
335         isHidden();
336         isDocOnly();
337         parseRegex(mText);
338         parseBriefTags();
339         mText = null;
340         mInitialized = true;
341
342         mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
343         mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
344         mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
345         mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
346         mReturnTags = ParsedTagInfo.joinTags(mReturnTagsList.toArray(
347                                              new ParsedTagInfo[mReturnTagsList.size()]));
348         mDeprecatedTags = ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(
349                                         new ParsedTagInfo[mDeprecatedTagsList.size()]));
350         mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
351         mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
352         mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
353
354         mParamTagsList = null;
355         mSeeTagsList = null;
356         mThrowsTagsList = null;
357         mReturnTagsList = null;
358         mDeprecatedTagsList = null;
359         mUndeprecateTagsList = null;
360         mAttrTagsList = null;
361         mBriefTagsList = null;
362     }
363
364     boolean mInitialized;
365     int mHidden = -1;
366     int mDocOnly = -1;
367     String mText;
368     ContainerInfo mBase;
369     SourcePositionInfo mPosition;
370     int mLine = 1;
371
372     TagInfo[] mInlineTags;
373     TagInfo[] mTags;
374     ParamTagInfo[] mParamTags;
375     SeeTagInfo[] mSeeTags;
376     ThrowsTagInfo[] mThrowsTags;
377     TagInfo[] mBriefTags;
378     TagInfo[] mReturnTags;
379     TagInfo[] mDeprecatedTags;
380     TagInfo[] mUndeprecateTags;
381     AttrTagInfo[] mAttrTags;
382
383     ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
384     ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
385     ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
386     ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
387     ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
388     ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
389     ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
390     ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
391     ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
392     ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
393
394
395 }