001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * File : CommentGather.java
044: * Created on : Oct 23, 2003
045: * Author : Aztec
046: */
047: package org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework;
048:
049: import java.util.ArrayList;
050: import java.util.Hashtable;
051: import java.util.Set;
052: import java.util.StringTokenizer;
053:
054: import antlr.CommonHiddenStreamToken;
055: import antlr.collections.AST;
056: import antlr.*;
057:
058: /**
059: * @author Aztec
060: */
061: public class CommentGather implements ICommentGather {
062: protected int m_SLCOMMENT;
063: protected int m_MLCOMMENT;
064:
065: public CommentGather() {
066: }
067:
068: public CommentGather(int slComment, int mlComment) {
069: m_SLCOMMENT = slComment;
070: m_MLCOMMENT = mlComment;
071: }
072:
073: /* (non-Javadoc)
074: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ICommentGather#gather(antlr.collections.AST, org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenDescriptor)
075: */
076: public ITokenDescriptor gather(AST pAST, ITokenDescriptor pDesc) {
077: if (pAST == null)
078: return pDesc;
079:
080: if (pDesc == null)
081: pDesc = new TokenDescriptor();
082:
083: CommonASTWithLocationsAndHidden pToken = null;
084:
085: try {
086: pToken = (CommonASTWithLocationsAndHidden) pAST;
087: } catch (ClassCastException e) {
088: e.printStackTrace();
089: }
090:
091: if (pToken == null)
092: return null;
093:
094: CommonHiddenStreamToken pHiddenToken = (CommonHiddenStreamToken) pToken
095: .getHiddenBefore();
096:
097: int startLine = -1;
098: int startColumn = -1;
099: long startPos = -1;
100: int length = -1;
101:
102: boolean processingComment = false;
103: String comment = "";
104:
105: boolean markerFound = false;
106: boolean processAsUsually = false;
107: boolean processCached = false;
108: int state = 0;
109: CommonHiddenStreamToken cached1 = null;
110: CommonHiddenStreamToken cached2 = null;
111: Hashtable<String, MarkerKeyTokenDescriptor> parsedValues = null;
112:
113: while (pHiddenToken != null) {
114: int type = pHiddenToken.getType();
115:
116: if (type == getSingleLineType()
117: || type == getMultiLineType()) {
118: processAsUsually = markerFound;
119: // parsing id marker possibly enclosed into folding comment tags
120: if (!markerFound) {
121: processCached = false;
122: if (type == getSingleLineType()) {
123: if (state == 0 || state == 1) {
124: parsedValues = new Hashtable<String, MarkerKeyTokenDescriptor>();
125: }
126: if (state == 0) {
127: cached1 = null;
128: cached2 = null;
129: }
130: if (state == 0) {
131: if (parseEditorFoldComment(pHiddenToken
132: .getText(), false)) {
133: if (parseMarkerComment(pHiddenToken
134: .getText(), parsedValues,
135: pHiddenToken.getPosition())) {
136: cached2 = pHiddenToken;
137: state = 2;
138: } else {
139: cached1 = pHiddenToken;
140: state = 1;
141: }
142: } else if (parseMarkerComment(pHiddenToken
143: .getText(), parsedValues,
144: pHiddenToken.getPosition())) {
145: storeMarkerComment(
146: new CommonHiddenStreamToken[] { pHiddenToken },
147: parsedValues, pDesc);
148: markerFound = true;
149: } else {
150: processAsUsually = true;
151: }
152: } else if (state == 1) {
153: if (parseMarkerComment(pHiddenToken
154: .getText(), parsedValues,
155: pHiddenToken.getPosition())) {
156: cached2 = pHiddenToken;
157: state = 2;
158: } else {
159: processCached = true;
160: processAsUsually = true;
161: state = 0;
162: }
163: } else if (state == 2) {
164: if (parseEditorFoldComment(pHiddenToken
165: .getText(), true)) {
166: storeMarkerComment(
167: new CommonHiddenStreamToken[] {
168: cached1, cached2,
169: pHiddenToken },
170: parsedValues, pDesc);
171: } else {
172: storeMarkerComment(
173: new CommonHiddenStreamToken[] { cached2 },
174: parsedValues, pDesc);
175: processCached = true;
176: processAsUsually = true;
177: }
178: markerFound = true;
179: }
180: } else {
181: if (cached2 != null) {
182: storeMarkerComment(
183: new CommonHiddenStreamToken[] { cached2 },
184: parsedValues, pDesc);
185: markerFound = true;
186: }
187: processCached = true;
188: processAsUsually = true;
189: }
190: }
191: if (cached1 != null && processCached) {
192: comment = cleanseComment(cached1.getText(), cached1
193: .getType())
194: + comment;
195: startLine = cached1.getLine();
196: startColumn = cached1.getColumn();
197: startPos = cached1.getPosition();
198:
199: String value = cached1.getText();
200: length += value.length();
201:
202: processingComment = true;
203: }
204:
205: if (processAsUsually) {
206: comment = cleanseComment(pHiddenToken.getText(),
207: pHiddenToken.getType())
208: + comment;
209: startLine = pHiddenToken.getLine();
210: startColumn = pHiddenToken.getColumn();
211: startPos = pHiddenToken.getPosition();
212:
213: String value = pHiddenToken.getText();
214: length += value.length();
215:
216: processingComment = true;
217: }
218: }
219:
220: if (pHiddenToken != null && type != getMultiLineType()) {
221: pHiddenToken = pHiddenToken.getHiddenBefore();
222: } else if (type == getMultiLineType()) {
223: // If we have found a multiline comment there is no reason to continue.
224: // basically we only want to continue if the comment is a single line
225: // comment.
226: pHiddenToken = null;
227: }
228: }
229: //If found a comment I want to add it to the token descriptors property. Since the
230: // comment is optional for a token I am making it a property. The idea is that only
231: // required elements are fields on token descriptors. Also a comment is not really a
232: // entity of the specific token. I is really property of a state (class, operation, or attribute).
233: // However it is only able to be retrieved by a token.
234: if (comment != null && comment.trim().length() > 0) {
235: // If we fail I do not want to worry about it.
236: pDesc.addProperty("Comment", comment);
237: pDesc.addProperty("CommentStartLine", String
238: .valueOf(startLine));
239: pDesc.addProperty("CommentStartColumn", String
240: .valueOf(startColumn));
241: pDesc.addProperty("CommentStartPos", String
242: .valueOf(startPos));
243: pDesc.addProperty("CommentLength", String
244: .valueOf(length + 1));
245: }
246: return pDesc;
247: }
248:
249: /* (non-Javadoc)
250: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ICommentGather#getMultiLineType()
251: */
252: public int getMultiLineType() {
253: // TODO Auto-generated method stub
254: return m_MLCOMMENT;
255: }
256:
257: /* (non-Javadoc)
258: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ICommentGather#getSingleLineType()
259: */
260: public int getSingleLineType() {
261: // TODO Auto-generated method stub
262: return m_SLCOMMENT;
263: }
264:
265: protected String cleanseComment(String comment, int type) {
266: if (comment == null || comment.trim().length() == 0)
267: return comment;
268:
269: if (type == getSingleLineType()) {
270: return comment.replaceAll("^\\s*//\\s?", "");
271: } else {
272: return comment.replaceAll("/\\*\\s*|\\*/|\\*\\s?", "");
273: }
274:
275: }
276:
277: /**
278: * parses (in a very ad-hoc style) the line of the following format
279: * #[regen=yes,id=C2FEEEAC-CFCD-11D1-8B05-00600806D9B6]
280: */
281: public static boolean parseMarkerComment(String comment,
282: Hashtable<String, MarkerKeyTokenDescriptor> result,
283: long linePos) {
284: if (comment == null || result == null) {
285: return false;
286: }
287: long initPos = linePos;
288: int ws = 0;
289: while (Character.isWhitespace(comment.charAt(ws))) {
290: ws++;
291: }
292: initPos += ws;
293: String ln = comment.trim();
294: int cs = ln.indexOf("//");
295: if (cs == 0 && ln.length() > 5) {
296: ln = ln.substring(cs + 2).trim();
297: initPos += cs + 2;
298: }
299: if (ln.length() < 3) {
300: return false;
301: }
302: if (!(ln.charAt(0) == '#' && ln.charAt(1) == '[')) {
303: return false;
304: }
305: int start = 2;
306: int end = ln.indexOf("]", start);
307: if (end < 0) {
308: return false;
309: }
310: String values = ln.substring(start, end);
311: initPos += start;
312: int pnt = 0;
313: int len = end - start;
314: while (pnt < len) {
315: int commaAt = values.indexOf(",", pnt);
316: String pair = null;
317: if (commaAt < 0) {
318: commaAt = values.length();
319: }
320: pair = values.substring(pnt, commaAt);
321: if (pair != null) {
322: pair = pair.trim();
323: int ind = pair.indexOf("=");
324: if (ind > 0) {
325: String key = pair.substring(0, ind).trim();
326: String value = pair.substring(ind + 1,
327: pair.length()).trim();
328: MarkerKeyTokenDescriptor desc = new MarkerKeyTokenDescriptor();
329: desc.value = value;
330: desc.length = commaAt - pnt;
331: desc.startPos = initPos + pnt;
332: result.put(key, desc);
333: }
334: }
335: pnt = commaAt + 1;
336: }
337: return true;
338: }
339:
340: /**
341: * parses (in a very ad-hoc style - don't want to call full-fledge
342: * XML parsing, thus user isn't supposed to alterate these lines too much)
343: * the <editor-fold> start and end line
344: */
345: public static boolean parseEditorFoldComment(String comment,
346: boolean open) {
347: if (comment == null) {
348: return false;
349: }
350: String ln = comment.trim();
351: int cs = ln.indexOf("//");
352: if (cs == 0) {
353: ln = ln.substring(cs + 2).trim();
354: } else {
355: return false;
356: }
357:
358: if (open) {
359: if (ln.startsWith("<editor-fold")) {
360: return true;
361: }
362: } else {
363: if (ln.indexOf("</editor-fold") > -1) {
364: return true;
365: }
366: }
367: return false;
368: }
369:
370: private void storeMarkerComment(
371: CommonHiddenStreamToken[] pHiddenTokens,
372: Hashtable<String, MarkerKeyTokenDescriptor> parsedValues,
373: ITokenDescriptor pDesc) {
374: Set<String> keys = parsedValues.keySet();
375: for (String key : keys) {
376: MarkerKeyTokenDescriptor desc = parsedValues.get(key);
377: pDesc
378: .addProperty("Marker-" + key.toLowerCase(),
379: desc.value);
380: pDesc.addProperty("Marker-" + key.toLowerCase()
381: + "StartPos", new Long(desc.startPos).toString());
382: pDesc.addProperty("Marker-" + key.toLowerCase() + "Length",
383: new Integer(desc.length).toString());
384: }
385:
386: String commentMarker = "";
387: int startLineMarker = -1;
388: int startColumnMarker = -1;
389: long startPosMarker = -1;
390: int lengthMarker = -1;
391:
392: for (int i = 0; i < pHiddenTokens.length; i++) {
393: commentMarker = cleanseComment(pHiddenTokens[i].getText(),
394: pHiddenTokens[i].getType())
395: + commentMarker;
396: startLineMarker = pHiddenTokens[i].getLine();
397: startColumnMarker = pHiddenTokens[i].getColumn();
398: startPosMarker = pHiddenTokens[i].getPosition();
399: lengthMarker += pHiddenTokens[i].getText().length();
400: }
401:
402: pDesc.addProperty("Marker-Comment", commentMarker);
403: pDesc.addProperty("Marker-CommentStartLine", String
404: .valueOf(startLineMarker));
405: pDesc.addProperty("Marker-CommentStartColumn", String
406: .valueOf(startColumnMarker));
407: pDesc.addProperty("Marker-CommentStartPos", String
408: .valueOf(startPosMarker));
409: pDesc.addProperty("Marker-CommentLength", String
410: .valueOf(lengthMarker + 1));
411: }
412:
413: static class MarkerKeyTokenDescriptor {
414: String value;
415: long startPos = -1;
416: int length = -1;
417: }
418:
419: }
|