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: package org.netbeans.modules.cnd.modelimpl.csm.core;
043:
044: import antlr.ASTVisitor;
045: import antlr.collections.AST;
046: import java.io.BufferedInputStream;
047: import java.io.BufferedOutputStream;
048: import java.io.File;
049: import java.io.FileInputStream;
050: import java.io.FileOutputStream;
051: import java.io.IOException;
052: import java.io.ObjectInputStream;
053: import java.io.ObjectOutputStream;
054: import java.io.PrintStream;
055: import java.util.ArrayList;
056: import java.util.List;
057: import org.netbeans.modules.cnd.utils.cache.TextCache;
058: import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
059: import org.netbeans.modules.cnd.modelimpl.parser.generated.CPPTokenTypes;
060: import org.netbeans.modules.cnd.modelimpl.cache.impl.CacheUtil;
061: import org.netbeans.modules.cnd.modelimpl.debug.DiagnosticExceptoins;
062: import org.netbeans.modules.cnd.modelimpl.parser.CsmAST;
063:
064: /**
065: * Miscellaneous AST-related static utility functions
066: * @author Vladimir Kvasihn
067: */
068: public class AstUtil {
069:
070: public static boolean isEmpty(AST ast, boolean hasFakeChild) {
071: if (isEmpty(ast)) {
072: return true;
073: } else {
074: return hasFakeChild ? isEmpty(ast.getFirstChild()) : false;
075: }
076: }
077:
078: private static boolean isEmpty(AST ast) {
079: return (ast == null || ast.getType() == CPPTokenTypes.EOF);
080: }
081:
082: public static String[] getRawNameInChildren(AST ast) {
083: return getRawName(findIdToken(ast));
084: }
085:
086: public static String[] getRawName(AST token) {
087: List/*<String>*/l = new ArrayList/*<String>*/();
088: for (; token != null; token = token.getNextSibling()) {
089: switch (token.getType()) {
090: case CPPTokenTypes.ID:
091: l.add(token.getText());
092: break;
093: case CPPTokenTypes.SCOPE:
094: break;
095: default:
096: //TODO: process templates
097: break;
098: }
099: }
100: return (String[]) l.toArray(new String[l.size()]);
101: }
102:
103: private static AST findIdToken(AST ast) {
104: for (AST token = ast.getFirstChild(); token != null; token = token
105: .getNextSibling()) {
106: if (token.getType() == CPPTokenTypes.ID) {
107: return token;
108: } else if (token.getType() == CPPTokenTypes.CSM_QUALIFIED_ID) {
109: return token.getFirstChild();
110: }
111: }
112: return null;
113: }
114:
115: public static String findId(AST ast) {
116: return findId(ast, -1);
117: }
118:
119: /**
120: * Finds ID (either CPPTokenTypes.CSM_QUALIFIED_ID or CPPTokenTypes.ID)
121: * in direct children of the given AST tree
122: *
123: * @param ast tree to secarch ID in
124: *
125: * @param limitingTokenType type of token that, if being found, stops search
126: * -1 means that there is no such token.
127: * This parameter allows, for example, searching until "}" is encountered
128: * @return found id
129: */
130: public static String findId(AST ast, int limitingTokenType) {
131: return findId(ast, limitingTokenType, false);
132: }
133:
134: /**
135: * Finds ID (either CPPTokenTypes.CSM_QUALIFIED_ID or CPPTokenTypes.ID)
136: * in direct children of the given AST tree
137: *
138: * @param ast tree to secarch ID in
139: *
140: * @param limitingTokenType type of token that, if being found, stops search
141: * -1 means that there is no such token.
142: * This parameter allows, for example, searching until "}" is encountered
143: * @param qualified flag indicating if full qualified id is needed
144: * @return id
145: */
146: public static String findId(AST ast, int limitingTokenType,
147: boolean qualified) {
148: for (AST token = ast.getFirstChild(); token != null; token = token
149: .getNextSibling()) {
150: int type = token.getType();
151: if (type == limitingTokenType && limitingTokenType >= 0) {
152: return null;
153: } else if (type == CPPTokenTypes.ID) {
154: return token.getText();
155: } else if (type == CPPTokenTypes.CSM_QUALIFIED_ID) {
156: if (qualified) {
157: return token.getText();
158: }
159: AST last = getLastChild(token);
160: if (last != null) {
161: if (last.getType() == CPPTokenTypes.ID) {
162: return last.getText();
163: } else {
164: AST first = token.getFirstChild();
165: if (first.getType() == CPPTokenTypes.LITERAL_OPERATOR) {
166: StringBuilder sb = new StringBuilder(first
167: .getText());
168: sb.append(' ');
169: AST next = first.getNextSibling();
170: if (next != null) {
171: sb.append(next.getText());
172: }
173: return TextCache.getString(sb.toString())
174: .toString();
175: } else if (first.getType() == CPPTokenTypes.ID) {
176: return first.getText();
177: }
178: }
179: }
180: }
181: }
182: return "";
183: }
184:
185: public static AST findMethodName(AST ast) {
186: AST type = ast.getFirstChild(); // type
187: AST qn = null;
188: int i = 0;
189: while (type != null) {
190: switch (type.getType()) {
191: case CPPTokenTypes.LESSTHAN:
192: i++;
193: type = type.getNextSibling();
194: continue;
195: case CPPTokenTypes.GREATERTHAN:
196: i--;
197: type = type.getNextSibling();
198: continue;
199: case CPPTokenTypes.CSM_TYPE_BUILTIN:
200: case CPPTokenTypes.CSM_TYPE_COMPOUND:
201: type = type.getNextSibling();
202: if (i == 0) {
203: qn = type;
204: }
205: continue;
206: case CPPTokenTypes.CSM_QUALIFIED_ID:
207: if (i == 0) {
208: qn = type;
209: }
210: type = type.getNextSibling();
211: continue;
212: case CPPTokenTypes.CSM_COMPOUND_STATEMENT:
213: case CPPTokenTypes.CSM_COMPOUND_STATEMENT_LAZY:
214: case CPPTokenTypes.COLON:
215: break;
216: default:
217: type = type.getNextSibling();
218: continue;
219: }
220: break;
221: }
222: return qn;
223: }
224:
225: public static boolean hasChildOfType(AST ast, int type) {
226: for (AST token = ast.getFirstChild(); token != null; token = token
227: .getNextSibling()) {
228: if (token.getType() == type) {
229: return true;
230: }
231: }
232: return false;
233: }
234:
235: public static AST findChildOfType(AST ast, int type) {
236: for (AST token = ast.getFirstChild(); token != null; token = token
237: .getNextSibling()) {
238: if (token.getType() == type) {
239: return token;
240: }
241: }
242: return null;
243: }
244:
245: public static AST findSiblingOfType(AST ast, int type) {
246: for (AST token = ast; token != null; token = token
247: .getNextSibling()) {
248: if (token.getType() == type) {
249: return token;
250: }
251: }
252: return null;
253: }
254:
255: public static AST getLastChild(AST token) {
256: if (token == null) {
257: return null;
258: }
259: AST child = token.getFirstChild();
260: if (child != null) {
261: while (child.getNextSibling() != null) {
262: child = child.getNextSibling();
263: }
264: return child;
265: }
266: return null;
267: }
268:
269: public static AST getLastChildRecursively(AST token) {
270: if (token == null) {
271: return null;
272: }
273: if (token.getFirstChild() == null) {
274: return token;
275: } else {
276: AST child = getLastChild(token);
277: return getLastChildRecursively(child);
278: }
279: }
280:
281: public static CsmAST getFirstCsmAST(AST node) {
282: if (node != null) {
283: if (node instanceof CsmAST) {
284: return (CsmAST) node;
285: } else {
286: return getFirstCsmAST(node.getFirstChild());
287: }
288: }
289: return null;
290: }
291:
292: public static void toStream(AST ast, final PrintStream ps) {
293: ASTVisitor impl = new ASTVisitor() {
294: public void visit(AST node) {
295: print(node, ps);
296: for (AST node2 = node; node2 != null; node2 = node2
297: .getNextSibling()) {
298: if (node2.getFirstChild() != null) {
299: ps.print('>');
300: visit(node2.getFirstChild());
301: ps.print('<');
302: }
303: }
304: }
305: };
306: impl.visit(ast);
307: }
308:
309: private static void print(AST ast, PrintStream ps) {
310: ps.print('[');
311: ps.print(ast.getText());
312: ps.print('(');
313: ps.print(ast.getType());
314: ps.print(')');
315: ps.print(ast.getLine());
316: ps.print(':');
317: ps.print(ast.getColumn());
318: ps.print(']');
319: //ps.print('\n');
320: }
321:
322: private static int fileIndex = 0;
323:
324: public static AST testASTSerialization(FileBuffer buffer, AST ast) {
325: AST astRead = null;
326: File file = buffer.getFile();
327: // testing caching ast
328: String prefix = "cnd_modelimpl_" + (fileIndex++); // NOI18N
329: String suffix = file.getName();
330: try {
331: File out = File.createTempFile(prefix, suffix);
332: if (false)
333: System.err.println("...saving AST of file "
334: + file.getAbsolutePath() + " into tmp file "
335: + out); // NOI18N
336: long astTime = System.currentTimeMillis();
337: // write
338: ObjectOutputStream oos = new ObjectOutputStream(
339: new BufferedOutputStream(new FileOutputStream(out),
340: TraceFlags.BUF_SIZE));
341: try {
342: CacheUtil.writeAST(oos, ast);
343: } finally {
344: oos.close();
345: }
346: long writeTime = System.currentTimeMillis() - astTime;
347: if (false)
348: System.err.println("saved AST of file "
349: + file.getAbsolutePath() + " withing "
350: + writeTime + "ms"); // NOI18N
351: astTime = System.currentTimeMillis();
352: // read
353: ObjectInputStream ois = new ObjectInputStream(
354: new BufferedInputStream(new FileInputStream(out),
355: TraceFlags.BUF_SIZE));
356: try {
357: astRead = CacheUtil.readAST(ois);
358: } catch (ClassNotFoundException ex) {
359: DiagnosticExceptoins.register(ex);
360: } finally {
361: ois.close();
362: }
363: long readTime = System.currentTimeMillis() - astTime;
364: if (false)
365: System.err.println("read AST of file "
366: + file.getAbsolutePath() + " withing "
367: + readTime + "ms"); // NOI18N
368: out.delete();
369: } catch (IOException ex) {
370: DiagnosticExceptoins.register(ex);
371: }
372: return astRead;
373: }
374: }
|