/** *Constructlanguagebyprovidingacollectionoftokenids *thatcomprisethelanguageandextracategoriesintowhichthetokenidsbelong. * *@paramlanguageHierarchynon-nulllanguagehierarchyisinone-to-onerelationship *withthelanguageandrepresentsitonSPIside. *@throwsIndexOutOfBoundsExceptionifanytokenid'sordinalis<0.
*/
Language(LanguageHierarchy<T> languageHierarchy) { // Search for an empty id int lid = 0; synchronized (Language.class) { for (int i = 0; i < languageRefList.size(); i++) {
Reference<Language<?>> langRef = languageRefList.get(i); if (langRef.get() == null) { // Released already
lid = i + 1;
languageRefList.set(i, new WeakReference<Language<?>>(this)); break;
}
} if (lid == 0) {
lid = languageRefList.size() + 1;
languageRefList.add(new WeakReference<Language<?>>(this));
}
} this.id = lid;
this.languageHierarchy = languageHierarchy; this.languageOperation = new LanguageOperation<T>(languageHierarchy, this);
mimeType = LexerSpiPackageAccessor.get().mimeType(languageHierarchy);
checkMimeTypeValid(mimeType); // Create ids and find max ordinal
Collection<T> createdIds = LexerSpiPackageAccessor.get().createTokenIds(languageHierarchy); if (createdIds == null) thrownew IllegalArgumentException("Ids cannot be null"); // NOI18N
maxOrdinal = TokenIdSet.findMaxOrdinal(createdIds);
// Convert collection of ids to efficient indexed Set<T> if (createdIds instanceof EnumSet) {
ids = (Set<T>)createdIds;
} else { // not EnumSet
ids = new TokenIdSet<T>(createdIds, maxOrdinal, true);
}
// Create TokenIdSet instances for token categories
Map<String,Collection<T>> createdCat2ids
= LexerSpiPackageAccessor.get().createTokenCategories(languageHierarchy); if (createdCat2ids == null) {
createdCat2ids = Collections.emptyMap();
}
cat2ids = new HashMap<String,Set<T>>((int)(createdCat2ids.size() / 0.73f)); for (Map.Entry<String,Collection<T>> entry : createdCat2ids.entrySet()) {
Collection<T> createdCatIds = entry.getValue();
TokenIdSet.checkIdsFromLanguage(createdCatIds, ids); // Do not use the original createdCatIds set because of the following: // 1) Two token categories will have the same sets of contained ids // in the createdCatIds map (the same physical Set instance). // 2) At least one token id will have one of the two categories // as its primary category. // 3) If the original Set instance from the createdCatIds would be used // then both categories would incorrectly contain the extra id(s).
Set<T> catIds = new TokenIdSet<T>(createdCatIds, maxOrdinal, false);
cat2ids.put(entry.getKey(), catIds);
}
// Walk through all ids and check duplicate names and primary categories
idName2id = new HashMap<String,T>((int)(ids.size() / 0.73f)); for (T id : ids) {
T sameNameId = idName2id.put(id.name(), id); if (sameNameId != null && sameNameId != id) { // token ids with same name thrownew IllegalArgumentException(id + " has duplicate name with " + sameNameId);
}
/** *GettokenIdforthegivenordinal.Thismethod *canbeusedbylexerstoquicklytranslateordinal *totokenId. *@paramordinalordinaltobetranslatedtocorrespondingtokenId. *@returnvalidtokenIdornullifthere'snocorresponding *tokenIdforthegivenint-id.It'spossiblebecauseintIds *ofthelanguage'stokenidsdonotneedtobecontinuous. *Iftheordinalis<0orhigherthanthehighest *ordinalofallthetokenidsofthislanguagethemethod *throws{@linkIndexOutOfBoundsException}. *@throwsIndexOutOfBoundsExceptioniftheordinalis *<0orhigherthan{@link#maxOrdinal()}.
*/ public T tokenId(int ordinal) { synchronized (idName2id) { if (indexedIds == null) { if (ids instanceof EnumSet) {
indexedIds = new TokenIdSet<T>(ids, maxOrdinal, false);
} else { // not EnumSet
indexedIds = (TokenIdSet<T>)ids;
}
} return indexedIds.indexedIds()[ordinal];
}
}
/** *Similarto{@link#tokenId(int)}howeveritguarantees *thatitwillalwaysreturnnon-nulltokenId.Typicallyforalexer *justbeingdevelopedit'spossiblethattherearesomeinteger *tokenidsdefinedinthegeneratedlexerforwhichthereis *nocorrespondenceinthelanguage.Thelexerwrappershould *alwayscallthismethodifitexpectstofindavalid *counterpartforgivenintegerid. *@paramordinalordinaltotranslatetotokenid. *@returnalwaysnon-nulltokenIdthatcorrespondstothegivenintegerid. *@throwsIndexOutOfBoundsExceptioniftheordinalis *<0orhigherthan{@link#maxOrdinal()}orwhenthereisnocorresponding *tokenidforit.
*/ public T validTokenId(int ordinal) {
T id = tokenId(ordinal); if (id == null) { thrownew IndexOutOfBoundsException("No tokenId for ordinal=" + ordinal
+ " in language " + this);
} return id;
}
/** *FindthetokenIdfromitsname. *@paramnamenameofthetokenIdtofind. *@returntokenIdwiththerequestednameornullifitdoesnotexist.
*/ public T tokenId(String name) { return idName2id.get(name);
}
/** *Similarto{@link#tokenId(String)}butguaranteesavalidtokenIdtobereturned. *@throwsIllegalArgumentExceptionifnotokeninthislanguagehasthegivenname.
*/ public T validTokenId(String name) {
T id = tokenId(name); if (id == null) { thrownew IllegalArgumentException("No tokenId for name=\"" + name
+ "\" in language " + this);
} return id;
}
/** The languages are equal only if they are the same objects. */ public @Override boolean equals(Object obj) { returnsuper.equals(obj);
}
/** The hashCode of the language is the identity hashCode. */ public @Override int hashCode() { returnsuper.hashCode();
}
privatevoid buildTokenIdCategories() {
assignCatArrays(); // List for decreasing of the number of created maps // for tokenId2category mappings. // List.get(0) is a Map[category, list-of-[category]]. // List.get(1) is a Map[category1, Map[category2, list-of-[category1;category2]]]. // etc.
List<Map<String,Object>> catMapsList = new ArrayList<Map<String,Object>>(4); // All categories for a single token id
List<String> idCats = new ArrayList<String>(4); for (T id : ids) { // No extra sorting of the categories in which the particular id is contained // - making explicit order of the categories could possibly be acomplished // in the future if necessary by supporting some extra hints // Add all the categories for the particular id into idCats for (Map.Entry<String,Set<T>> e : cat2ids.entrySet()) { if (e.getValue().contains(id)) {
idCats.add(e.getKey()); // Add this category to id's categories
}
} // Assign both non-primary cats and all cats
id2cats[id.ordinal()] = findCatList(catMapsList, idCats, 0);
id2nonPrimaryCats[id.ordinal()] = findCatList(catMapsList, idCats, 1);
idCats.clear(); // reuse the list (is cloned if added to catMapsList)
}
}
/** *FindthecachedlistofcategoriesfromthecatMapsList *fortheparticulartemporarilycollectedlistofcategories. * *@paramcatMapsListnon-nulllistofcachedmaps. *<br> *List.get(0)isaMap[category,list-containing-[category]]. *<br> *List.get(1)isaMap[category1,Map[category2,list-containing-[category1;category2]]]. *<br> *etc. * *@paramidCatsnon-nulltemporarilycollectedlistofcategoriesfortheparticularid. *Itmaybemodifiedafterthismethodgetsfinished. *@paramstartIndex>=0startingindexinidCats-either0forreturning *ofallcategoriesor1forreturningnon-primarycategories. *@returnnon-nullcachedlistofcategorieswithcontentsequaltoidCats.
*/ privatestatic List<String> findCatList(List<Map<String,Object>> catMapsList, List<String> idCats, int startIndex) { int size = idCats.size() - startIndex; if (size <= 0) { return Collections.emptyList();
} while (catMapsList.size() < size) {
catMapsList.add(new HashMap<String,Object>());
} // Find the catList as the last item in the cascaded search through the maps
Map<String,Object> m = catMapsList.get(--size); for (int i = startIndex; i < size; i++) {
@SuppressWarnings("unchecked")
Map<String,Object> catMap = (Map<String,Object>)m.get(idCats.get(i)); if (catMap == null) {
catMap = new HashMap<String,Object>(); // Map<String,Map<String,Object>>
m.put(idCats.get(i), catMap);
}
m = catMap;
}
privatevoid checkMemberId(T id) { if (!ids.contains(id)) { thrownew IllegalArgumentException(id + " does not belong to language " + this); // NOI18N
}
}
privatestaticvoid checkMimeTypeValid(String mimeType) { if (mimeType == null) { thrownew IllegalStateException("mimeType cannot be null"); // NOI18N
} int slashIndex = mimeType.indexOf('/'); if (slashIndex == -1) { // no slash thrownew IllegalStateException("mimeType=" + mimeType + " does not contain '/'"); // NOI18N
} if (mimeType.indexOf('/', slashIndex + 1) != -1) { thrownew IllegalStateException("mimeType=" + mimeType + " contains more than one '/'"); // NOI18N
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.