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-2006 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: package org.netbeans.cnd.api.lexer;
042:
043: import javax.swing.text.Document;
044: import javax.swing.text.JTextComponent;
045: import org.netbeans.api.lexer.Language;
046: import org.netbeans.api.lexer.TokenHierarchy;
047: import org.netbeans.api.lexer.TokenSequence;
048: import org.netbeans.modules.cnd.lexer.PreprocLexer;
049:
050: /**
051: *
052: * @author Vladirmir Voskresensky
053: */
054: public final class CndLexerUtilities {
055:
056: public static String C_MIME_TYPE = "text/x-c";// NOI18N
057: public static String CPLUSPLUS_MIME_TYPE = "text/x-c++"; // NOI18N
058: public static String PREPROC_MIME_TYPE = "text/x-preprocessor";// NOI18N
059: public static String LEXER_STATE = "lexer-state"; // NOI18N
060: public static String LEXER_FILTER = "lexer-filter"; // NOI18N
061: public static int PREPROC_STATE_IN_BODY = PreprocLexer.OTHER;
062:
063: private CndLexerUtilities() {
064: }
065:
066: public static TokenSequence<CppTokenId> getCppTokenSequence(
067: final JTextComponent component, final int offset) {
068: Document doc = component.getDocument();
069: return getCppTokenSequence(doc, offset);
070: }
071:
072: public static Language<CppTokenId> getLanguage(String mime) {
073: if (C_MIME_TYPE.equals(mime)) {
074: return CppTokenId.languageC();
075: } else if (CPLUSPLUS_MIME_TYPE.equals(mime)) {
076: return CppTokenId.languageCpp();
077: }
078: return null;
079: }
080:
081: public static Language<CppTokenId> getLanguage(final Document doc) {
082: // try from property
083: Language lang = (Language) doc.getProperty(Language.class);
084: if (lang == null
085: || (lang != CppTokenId.languageC() && lang != CppTokenId
086: .languageCpp())) {
087: lang = getLanguage((String) doc.getProperty("mimeType")); // NOI18N
088: }
089: return (Language<CppTokenId>) lang;
090: }
091:
092: public static TokenSequence<CppTokenId> getCppTokenSequence(
093: final Document doc, final int offset) {
094: TokenHierarchy th = doc != null ? TokenHierarchy.get(doc)
095: : null;
096: TokenSequence<CppTokenId> ts = th != null ? getCppTokenSequence(
097: th, offset)
098: : null;
099: return ts;
100: }
101:
102: @SuppressWarnings("unchecked")
103: public static TokenSequence<CppTokenId> getCppTokenSequence(
104: final TokenHierarchy hierarchy, final int offset) {
105: if (hierarchy != null) {
106: TokenSequence<?> ts = hierarchy.tokenSequence();
107: while (ts != null && (offset == 0 || ts.moveNext())) {
108: ts.move(offset);
109: if (ts.language() == CppTokenId.languageC()
110: || ts.language() == CppTokenId.languageCpp()
111: || ts.language() == CppTokenId
112: .languagePreproc()) {
113: return (TokenSequence<CppTokenId>) ts;
114: }
115: if (!ts.moveNext() && !ts.movePrevious()) {
116: return null;
117: }
118: ts = ts.embedded();
119: }
120: }
121: return null;
122: }
123:
124: public static boolean isCppIdentifierStart(char ch) {
125: return Character.isJavaIdentifierStart(ch);
126: }
127:
128: public static boolean isCppIdentifierStart(int codePoint) {
129: return Character.isJavaIdentifierStart(codePoint);
130: }
131:
132: public static boolean isCppIdentifierPart(char ch) {
133: return Character.isJavaIdentifierPart(ch);
134: }
135:
136: public static boolean isCppIdentifierPart(int codePoint) {
137: return Character.isJavaIdentifierPart(codePoint);
138: }
139:
140: public static CharSequence removeEscapedLF(CharSequence text,
141: boolean escapedLF) {
142: if (!escapedLF) {
143: return text;
144: } else {
145: StringBuilder buffer = new StringBuilder();
146: int lengthM1 = text.length() - 1;
147: for (int i = 0; i <= lengthM1; i++) {
148: char c = text.charAt(i);
149: boolean append = true;
150: if (c == '\\') { // check escaped LF
151: if ((i < lengthM1) && (text.charAt(i + 1) == '\r')) {
152: i++;
153: append = false;
154: }
155: if ((i < lengthM1) && (text.charAt(i + 1) == '\n')) {
156: i++;
157: append = false;
158: }
159: }
160: if (append) {
161: buffer.append(c);
162: }
163: }
164: return buffer.toString();
165: }
166: }
167:
168: // filters
169: private static Filter<CppTokenId> FILTER_STD_C;
170: private static Filter<CppTokenId> FILTER_GCC_C;
171: private static Filter<CppTokenId> FILTER_STD_CPP;
172: private static Filter<CppTokenId> FILTER_PREPRPOCESSOR;
173:
174: public static Filter<CppTokenId> getDefatultFilter(boolean cpp) {
175: return cpp ? getStdCppFilter() : getStdCFilter();
176: }
177:
178: public synchronized static Filter<CppTokenId> getPreprocFilter() {
179: if (FILTER_PREPRPOCESSOR == null) {
180: FILTER_PREPRPOCESSOR = new Filter<CppTokenId>();
181: addPreprocKeywords(FILTER_PREPRPOCESSOR);
182: }
183: return FILTER_PREPRPOCESSOR;
184: }
185:
186: public synchronized static Filter<CppTokenId> getStdCFilter() {
187: if (FILTER_STD_C == null) {
188: FILTER_STD_C = new Filter<CppTokenId>();
189: addCommonCCKeywords(FILTER_STD_C);
190: addCOnlyKeywords(FILTER_STD_C);
191: }
192: return FILTER_STD_C;
193: }
194:
195: public synchronized static Filter<CppTokenId> getGccCFilter() {
196: if (FILTER_GCC_C == null) {
197: FILTER_GCC_C = new Filter<CppTokenId>();
198: addCommonCCKeywords(FILTER_GCC_C);
199: addCOnlyKeywords(FILTER_GCC_C);
200: addGccOnlyKeywords(FILTER_GCC_C);
201: }
202: return FILTER_GCC_C;
203: }
204:
205: public synchronized static Filter<CppTokenId> getStdCppFilter() {
206: if (FILTER_STD_CPP == null) {
207: FILTER_STD_CPP = new Filter<CppTokenId>();
208: addCommonCCKeywords(FILTER_STD_CPP);
209: addCppOnlyKeywords(FILTER_STD_CPP);
210: }
211: return FILTER_STD_CPP;
212: }
213:
214: ////////////////////////////////////////////////////////////////////////////
215: // help methods
216:
217: private static void addPreprocKeywords(
218: Filter<CppTokenId> filterToModify) {
219: CppTokenId[] ids = new CppTokenId[] {
220: CppTokenId.PREPROCESSOR_IF,
221: CppTokenId.PREPROCESSOR_IFDEF,
222: CppTokenId.PREPROCESSOR_IFNDEF,
223: CppTokenId.PREPROCESSOR_ELSE,
224: CppTokenId.PREPROCESSOR_ELIF,
225: CppTokenId.PREPROCESSOR_ENDIF,
226: CppTokenId.PREPROCESSOR_DEFINE,
227: CppTokenId.PREPROCESSOR_UNDEF,
228: CppTokenId.PREPROCESSOR_INCLUDE,
229: CppTokenId.PREPROCESSOR_INCLUDE_NEXT,
230: CppTokenId.PREPROCESSOR_LINE,
231: CppTokenId.PREPROCESSOR_IDENT,
232: CppTokenId.PREPROCESSOR_PRAGMA,
233: CppTokenId.PREPROCESSOR_WARNING,
234: CppTokenId.PREPROCESSOR_ERROR, };
235: addToFilter(ids, filterToModify);
236: }
237:
238: private static void addCommonCCKeywords(
239: Filter<CppTokenId> filterToModify) {
240: CppTokenId[] ids = new CppTokenId[] { CppTokenId.AUTO,
241: CppTokenId.BREAK, CppTokenId.CASE, CppTokenId.CHAR,
242: CppTokenId.CONST, CppTokenId.CONTINUE,
243: CppTokenId.DEFAULT, CppTokenId.DO, CppTokenId.DOUBLE,
244: CppTokenId.ELSE, CppTokenId.ENUM, CppTokenId.EXTERN,
245: CppTokenId.FLOAT, CppTokenId.FOR, CppTokenId.GOTO,
246: CppTokenId.IF, CppTokenId.INT, CppTokenId.LONG,
247: CppTokenId.REGISTER, CppTokenId.RETURN,
248: CppTokenId.SHORT, CppTokenId.SIZNED, CppTokenId.SIZEOF,
249: CppTokenId.STATIC, CppTokenId.STRUCT,
250: CppTokenId.SWITCH, CppTokenId.TYPEDEF,
251: CppTokenId.UNION, CppTokenId.UNSIGNED, CppTokenId.VOID,
252: CppTokenId.VOLATILE, CppTokenId.WHILE, };
253: addToFilter(ids, filterToModify);
254: }
255:
256: private static void addCppOnlyKeywords(
257: Filter<CppTokenId> filterToModify) {
258: CppTokenId[] ids = new CppTokenId[] { CppTokenId.ASM, // gcc and C++
259: CppTokenId.BOOL, // C++
260: CppTokenId.CATCH, //C++
261: CppTokenId.CLASS, //C++
262: CppTokenId.CONST_CAST, // C++
263: CppTokenId.DELETE, // C++
264: CppTokenId.DYNAMIC_CAST, // C++
265: CppTokenId.EXPLICIT, // C++
266: CppTokenId.EXPORT, // C++
267: CppTokenId.FINALLY, //C++
268: CppTokenId.FRIEND, // C++
269: CppTokenId.INLINE, // gcc, C++, now in C also
270: CppTokenId.MUTABLE, // C++
271: CppTokenId.NAMESPACE, //C++
272: CppTokenId.NEW, //C++
273: CppTokenId.OPERATOR, // C++
274: CppTokenId.PRIVATE, //C++
275: CppTokenId.PROTECTED, //C++
276: CppTokenId.PUBLIC, // C++
277: CppTokenId.REINTERPRET_CAST, //C++
278: CppTokenId.STATIC_CAST, // C++
279: CppTokenId.TEMPLATE, //C++
280: CppTokenId.THIS, // C++
281: CppTokenId.THROW, //C++
282: CppTokenId.TRY, // C++
283: CppTokenId.TYPEID, //C++
284: CppTokenId.TYPENAME, //C++
285: CppTokenId.TYPEOF, // gcc, C++
286: CppTokenId.USING, //C++
287: CppTokenId.VIRTUAL, //C++
288: CppTokenId.WCHAR_T, // C++
289:
290: CppTokenId.TRUE, // C++
291: CppTokenId.FALSE, // C++
292: };
293: addToFilter(ids, filterToModify);
294: }
295:
296: private static void addCOnlyKeywords(
297: Filter<CppTokenId> filterToModify) {
298: CppTokenId[] ids = new CppTokenId[] { CppTokenId.INLINE, // gcc, C++, now in C also
299: CppTokenId.RESTRICT, // C
300: CppTokenId._BOOL, // C
301: CppTokenId._COMPLEX, // C
302: CppTokenId._IMAGINARY, // C
303: };
304: addToFilter(ids, filterToModify);
305: }
306:
307: private static void addGccOnlyKeywords(
308: Filter<CppTokenId> filterToModify) {
309: CppTokenId[] ids = new CppTokenId[] { CppTokenId.ASM, // gcc and C++
310: CppTokenId.INLINE, // gcc, C++, now in C also
311: CppTokenId.TYPEOF, // gcc, C++
312: };
313: addToFilter(ids, filterToModify);
314: }
315:
316: private static void addToFilter(CppTokenId[] ids,
317: Filter<CppTokenId> filterToModify) {
318: for (CppTokenId id : ids) {
319: assert id.fixedText() != null : "id " + id
320: + " must have fixed text";
321: filterToModify.addMatch(id.fixedText(), id);
322: }
323: }
324: }
|