KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > lexer > EmbeddingContainer


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.lib.lexer;
21
22 import org.netbeans.api.lexer.Language;
23 import org.netbeans.api.lexer.LanguagePath;
24 import org.netbeans.api.lexer.TokenHierarchyEventType;
25 import org.netbeans.api.lexer.TokenId;
26 import org.netbeans.lib.lexer.TokenHierarchyOperation;
27 import org.netbeans.lib.lexer.inc.TokenChangeInfo;
28 import org.netbeans.lib.lexer.inc.TokenHierarchyEventInfo;
29 import org.netbeans.spi.lexer.LanguageEmbedding;
30 import org.netbeans.lib.lexer.token.AbstractToken;
31
32
33 /**
34  * Embedding info contains information about all the embeddings
35  * for a particular token in a token list.
36  * <br>
37  * There can be one or more {@link EmbeddedTokenList} instances for each
38  * cotnained embedding.
39  * <p>
40  * There is an intent to not degrade performance significantly
41  * with each extra language embedding level so the token list maintains direct
42  * link to the root level.
43  *
44  * @author Miloslav Metelka
45  * @version 1.00
46  */

47
48 public final class EmbeddingContainer<T extends TokenId> {
49     
50     /** Flag for additional correctness checks (may degrade performance). */
51     private static final boolean testing = Boolean.getBoolean("netbeans.debug.lexer.test");
52     
53     /**
54      * Get embedded token list.
55      *
56      * @param tokenList non-null token list in which the token for which the embedding
57      * should be obtained resides.
58      * @param index &gt;=0 index of the token in the token list where the embedding
59      * should be obtained.
60      * @param language whether only language embeddding of the particular language
61      * was requested. It may be null if any embedding should be returned.
62      */

63     public static <T extends TokenId, ET extends TokenId> EmbeddedTokenList<ET> getEmbedding(
64     TokenList<T> tokenList, int index, Language<ET> language) {
65         EmbeddingContainer<T> ec;
66         AbstractToken<T> token;
67         EmbeddedTokenList<? extends TokenId> lastEtl = null;
68         synchronized (tokenList.root()) {
69             Object JavaDoc tokenOrEmbeddingContainer = tokenList.tokenOrEmbeddingContainer(index);
70             if (tokenOrEmbeddingContainer.getClass() == EmbeddingContainer.class) {
71                 // Embedding container exists
72
@SuppressWarnings JavaDoc("unchecked")
73                 EmbeddingContainer<T> ecUC = (EmbeddingContainer<T>)tokenOrEmbeddingContainer;
74                 ec = ecUC;
75                 ec.updateOffsets();
76
77                 EmbeddedTokenList<? extends TokenId> etl = ec.firstEmbedding();
78                 while (etl != null) {
79                     if (language == null || etl.languagePath().innerLanguage() == language) {
80                         @SuppressWarnings JavaDoc("unchecked")
81                         EmbeddedTokenList<ET> etlUC = (EmbeddedTokenList<ET>)etl;
82                         return etlUC;
83                     }
84                     lastEtl = etl;
85                     etl = etl.nextEmbedding();
86                 }
87                 token = ec.token();
88             } else {
89                 ec = null;
90                 @SuppressWarnings JavaDoc("unchecked")
91                 AbstractToken<T> t = (AbstractToken<T>)tokenOrEmbeddingContainer;
92                 token = t;
93                 if (token.isFlyweight()) { // embedding cannot exist for this flyweight token
94
return null;
95                 }
96             }
97
98             // Attempt to find default embedding
99
LanguagePath languagePath = tokenList.languagePath();
100             @SuppressWarnings JavaDoc("unchecked")
101             LanguageEmbedding<ET> embedding = (LanguageEmbedding<ET>) LexerUtilsConstants.findEmbedding(
102                     token, languagePath, tokenList.inputAttributes());
103             if (embedding != null && (language == null || language == embedding.language())
104                     && embedding.startSkipLength() + embedding.endSkipLength() <= token.length()
105             ) {
106                 if (ec == null) {
107                     ec = new EmbeddingContainer<T>(token);
108                     tokenList.wrapToken(index, ec);
109                 }
110                 LanguagePath embeddedLanguagePath = LanguagePath.get(languagePath,
111                         embedding.language());
112                 EmbeddedTokenList<ET> etl = new EmbeddedTokenList<ET>(ec,
113                         embeddedLanguagePath, embedding, null);
114                 if (lastEtl != null)
115                     lastEtl.setNextEmbedding(etl);
116                 else
117                     ec.setFirstEmbedding(etl);
118                 return etl;
119             }
120             return null;
121         }
122     }
123
124     /**
125      * Create custom embedding.
126      *
127      * @param tokenList non-null token list in which the token for which the embedding
128      * should be created resides.
129      * @param index &gt;=0 index of the token in the token list where the embedding
130      * should be created.
131      * @param embeddedLanguage non-null embedded language.
132      * @param startSkipLength &gt;=0 number of characters in an initial part of the token
133      * for which the language embedding is being create that should be excluded
134      * from the embedded section. The excluded characters will not be lexed
135      * and there will be no tokens created for them.
136      * @param endSkipLength &gt;=0 number of characters at the end of the token
137      * for which the language embedding is defined that should be excluded
138      * from the embedded section. The excluded characters will not be lexed
139      * and there will be no tokens created for them.
140      */

141     public static <T extends TokenId, ET extends TokenId> boolean createEmbedding(
142     TokenList<T> tokenList, int index, Language<ET> embeddedLanguage,
143     int startSkipLength, int endSkipLength, boolean joinSections) {
144         TokenHierarchyOperation<?,?> tokenHierarchyOperation = tokenList.tokenHierarchyOperation();
145         if (tokenHierarchyOperation == null) {
146             return false;
147         }
148         TokenList<? extends TokenId> root = tokenList.root();
149         // Only create embedddings for valid operations so not e.g. for removed token list
150
Object JavaDoc tokenOrEmbeddingContainer = tokenList.tokenOrEmbeddingContainer(index);
151         AbstractToken<T> token;
152         EmbeddingContainer<T> ec;
153         synchronized (root) {
154             if (tokenOrEmbeddingContainer.getClass() == EmbeddingContainer.class) {
155                 // Embedding container exists
156
@SuppressWarnings JavaDoc("unchecked")
157                 EmbeddingContainer<T> ecUC = (EmbeddingContainer<T>)tokenOrEmbeddingContainer;
158                 ec = ecUC;
159                 EmbeddedTokenList<? extends TokenId> etl = ec.firstEmbedding();
160                 while (etl != null) {
161                     if (embeddedLanguage == etl.languagePath().innerLanguage()) {
162                         return false; // already exists
163
}
164                     etl = etl.nextEmbedding();
165                 }
166                 token = ec.token();
167             } else {
168                 @SuppressWarnings JavaDoc("unchecked")
169                 AbstractToken<T> t = (AbstractToken<T>)tokenOrEmbeddingContainer;
170                 token = t;
171                 if (token.isFlyweight()) { // embedding cannot exist for this flyweight token
172
return false;
173                 }
174                 ec = new EmbeddingContainer<T>(token);
175                 tokenList.wrapToken(index, ec);
176             }
177         }
178         
179         // Token is now wrapped with the EmbeddingContainer and the embedding can be added
180

181         EmbeddedTokenList<ET> etl;
182         LanguageEmbedding<ET> embedding;
183         synchronized (root) {
184             if (startSkipLength + endSkipLength > token.length()) // Check for appropriate size
185
return false;
186             // Add the new embedding as the first one in the single-linked list
187
embedding = LanguageEmbedding.create(embeddedLanguage,
188                 startSkipLength, endSkipLength, joinSections);
189             LanguagePath languagePath = tokenList.languagePath();
190             LanguagePath embeddedLanguagePath = LanguagePath.get(languagePath, embeddedLanguage);
191             // Make the embedded token list to be the first in the list
192
etl = new EmbeddedTokenList<ET>(
193                     ec, embeddedLanguagePath, embedding, ec.firstEmbedding());
194             ec.setFirstEmbedding(etl);
195             // Increment mod count? - not in this case
196
}
197
198         // Fire the embedding creation to the clients
199
// Threading model may need to be changed if necessary
200
int aOffset = ec.tokenStartOffset();
201         TokenHierarchyEventInfo eventInfo = new TokenHierarchyEventInfo(
202                 tokenHierarchyOperation,
203                 TokenHierarchyEventType.EMBEDDING,
204                 aOffset, 0, "", 0
205         );
206         eventInfo.setAffectedStartOffset(aOffset);
207         eventInfo.setAffectedEndOffset(aOffset + token.length());
208         // Construct outer token change info
209
TokenChangeInfo<T> info = new TokenChangeInfo<T>(tokenList);
210         info.setIndex(index);
211         info.setOffset(aOffset);
212         //info.setAddedTokenCount(0);
213
eventInfo.setTokenChangeInfo(info);
214
215         TokenChangeInfo<ET> embeddedInfo = new TokenChangeInfo<ET>(etl);
216         embeddedInfo.setIndex(0);
217         embeddedInfo.setOffset(aOffset + embedding.startSkipLength());
218         // Should set number of added tokens directly?
219
// - would prevent further lazy embedded lexing so leave to zero for now
220
//info.setAddedTokenCount(0);
221
info.addEmbeddedChange(embeddedInfo);
222
223         // Fire the change
224
tokenHierarchyOperation.fireTokenHierarchyChanged(
225                     LexerApiPackageAccessor.get().createTokenChangeEvent(eventInfo));
226         return true;
227     }
228
229     private final AbstractToken<T> token; // 12 bytes (8-super + 4)
230

231     /**
232      * Cached modification count allows to determine whether the start offset
233      * needs to be recomputed.
234      */

235     private int cachedModCount; // 16 bytes
236

237     /**
238      * For mutable environment this field contains root token list of the hierarchy.
239      *
240      */

241     private final TokenList<? extends TokenId> rootTokenList; // 20 bytes
242

243     /**
244      * The token in the root token list to which this embedding container relates.
245      * <br/>
246      * For first-level embedding it is the same like value of branchToken variable
247      * but for deeper embeddings it points to the corresponding branch token
248      * in the root token list.
249      * <br/>
250      * It's used for getting of the start offset of the contained tokens
251      * and for getting of their text.
252      */

253     private final AbstractToken<? extends TokenId> rootToken; // 24 bytes
254

255     /**
256      * Cached start offset of the token for which this embedding container
257      * was created.
258      */

259     private int tokenStartOffset; // 28 bytes
260

261     /**
262      * First embedded token list in the single-linked list.
263      */

264     private EmbeddedTokenList<? extends TokenId> firstEmbedding; // 32 bytes
265

266     /**
267      * Difference between start offset of the first token in this token list
268      * against the start offset of the root token.
269      * <br>
270      * The offset gets refreshed upon <code>updateStartOffset()</code>.
271      */

272     private int rootTokenOffsetShift; // 52 bytes
273

274
275     public EmbeddingContainer(AbstractToken<T> token) {
276         this.token = token;
277         TokenList<T> embeddedTokenList = token.tokenList();
278         this.rootTokenList = embeddedTokenList.root();
279         this.rootToken = (embeddedTokenList.getClass() == EmbeddedTokenList.class)
280                 ? ((EmbeddedTokenList<? extends TokenId>)embeddedTokenList).rootToken()
281                 : token;
282         this.cachedModCount = -2; // must differ from root's one to sync offsets
283
updateOffsets();
284     }
285
286     public void updateOffsets() {
287         synchronized (rootTokenList) {
288             if (cachedModCount != rootTokenList.modCount()) {
289                 cachedModCount = rootTokenList.modCount();
290                 tokenStartOffset = token.offset(null);
291                 rootTokenOffsetShift = tokenStartOffset - rootToken.offset(null);
292             }
293         }
294     }
295
296     public AbstractToken<T> token() {
297         return token;
298     }
299
300     public TokenList<? extends TokenId> rootTokenList() {
301         return rootTokenList;
302     }
303     
304     public AbstractToken<? extends TokenId> rootToken() {
305         return rootToken;
306     }
307
308     public int tokenStartOffset() {
309         return tokenStartOffset;
310     }
311     
312     public int rootTokenOffsetShift() {
313         return rootTokenOffsetShift;
314     }
315     
316     public char charAt(int tokenRelOffset) {
317         return rootToken.charAt(rootTokenOffsetShift + tokenRelOffset);
318     }
319     
320     public EmbeddedTokenList<? extends TokenId> firstEmbedding() {
321         return firstEmbedding;
322     }
323     
324     void setFirstEmbedding(EmbeddedTokenList<? extends TokenId> firstEmbedding) {
325         this.firstEmbedding = firstEmbedding;
326     }
327
328 }
329
Popular Tags