1 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 47 48 public final class EmbeddingContainer<T extends TokenId> { 49 50 51 private static final boolean testing = Boolean.getBoolean("netbeans.debug.lexer.test"); 52 53 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 tokenOrEmbeddingContainer = tokenList.tokenOrEmbeddingContainer(index); 70 if (tokenOrEmbeddingContainer.getClass() == EmbeddingContainer.class) { 71 @SuppressWarnings ("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 ("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 ("unchecked") 91 AbstractToken<T> t = (AbstractToken<T>)tokenOrEmbeddingContainer; 92 token = t; 93 if (token.isFlyweight()) { return null; 95 } 96 } 97 98 LanguagePath languagePath = tokenList.languagePath(); 100 @SuppressWarnings ("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 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 Object tokenOrEmbeddingContainer = tokenList.tokenOrEmbeddingContainer(index); 151 AbstractToken<T> token; 152 EmbeddingContainer<T> ec; 153 synchronized (root) { 154 if (tokenOrEmbeddingContainer.getClass() == EmbeddingContainer.class) { 155 @SuppressWarnings ("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; } 164 etl = etl.nextEmbedding(); 165 } 166 token = ec.token(); 167 } else { 168 @SuppressWarnings ("unchecked") 169 AbstractToken<T> t = (AbstractToken<T>)tokenOrEmbeddingContainer; 170 token = t; 171 if (token.isFlyweight()) { return false; 173 } 174 ec = new EmbeddingContainer<T>(token); 175 tokenList.wrapToken(index, ec); 176 } 177 } 178 179 181 EmbeddedTokenList<ET> etl; 182 LanguageEmbedding<ET> embedding; 183 synchronized (root) { 184 if (startSkipLength + endSkipLength > token.length()) return false; 186 embedding = LanguageEmbedding.create(embeddedLanguage, 188 startSkipLength, endSkipLength, joinSections); 189 LanguagePath languagePath = tokenList.languagePath(); 190 LanguagePath embeddedLanguagePath = LanguagePath.get(languagePath, embeddedLanguage); 191 etl = new EmbeddedTokenList<ET>( 193 ec, embeddedLanguagePath, embedding, ec.firstEmbedding()); 194 ec.setFirstEmbedding(etl); 195 } 197 198 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 TokenChangeInfo<T> info = new TokenChangeInfo<T>(tokenList); 210 info.setIndex(index); 211 info.setOffset(aOffset); 212 eventInfo.setTokenChangeInfo(info); 214 215 TokenChangeInfo<ET> embeddedInfo = new TokenChangeInfo<ET>(etl); 216 embeddedInfo.setIndex(0); 217 embeddedInfo.setOffset(aOffset + embedding.startSkipLength()); 218 info.addEmbeddedChange(embeddedInfo); 222 223 tokenHierarchyOperation.fireTokenHierarchyChanged( 225 LexerApiPackageAccessor.get().createTokenChangeEvent(eventInfo)); 226 return true; 227 } 228 229 private final AbstractToken<T> token; 231 235 private int cachedModCount; 237 241 private final TokenList<? extends TokenId> rootTokenList; 243 253 private final AbstractToken<? extends TokenId> rootToken; 255 259 private int tokenStartOffset; 261 264 private EmbeddedTokenList<? extends TokenId> firstEmbedding; 266 272 private int rootTokenOffsetShift; 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; 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 |