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:
042: package org.netbeans.modules.languages;
043:
044: import java.beans.PropertyChangeEvent;
045: import java.beans.PropertyChangeListener;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.util.ArrayList;
049: import java.util.HashMap;
050: import java.util.HashSet;
051: import java.util.Iterator;
052: import java.util.Map;
053: import java.util.Set;
054: import java.util.List;
055:
056: import javax.swing.event.EventListenerList;
057: import org.netbeans.api.languages.ASTNode;
058: import org.netbeans.api.languages.LanguageDefinitionNotFoundException;
059: import org.netbeans.api.languages.ParseException;
060: import org.netbeans.api.lexer.TokenId;
061: import org.netbeans.modules.languages.parser.LLSyntaxAnalyser;
062: import org.netbeans.modules.languages.parser.Parser;
063:
064: /**
065: *
066: * @author Jan Jancura
067: */
068: public class LanguageImpl extends Language {
069:
070: public static final String IMPORT_FEATURE = "IMPORT";
071:
072: private NBSLanguageReader reader;
073: private String mimeType;
074: private Parser parser;
075: private LLSyntaxAnalyser analyser;
076: private FeatureList featureList = new FeatureList();
077:
078: /** Creates a new instance of Language */
079: public LanguageImpl(String mimeType, NBSLanguageReader reader) {
080: this .mimeType = mimeType;
081: this .reader = reader;
082: }
083:
084: // public methods ..........................................................
085:
086: public String getMimeType() {
087: return mimeType;
088: }
089:
090: public Parser getParser() {
091: return parser;
092: }
093:
094: public LLSyntaxAnalyser getAnalyser() {
095: if (analyser == null)
096: analyser = LLSyntaxAnalyser.createEmpty(this );
097: return analyser;
098: }
099:
100: public FeatureList getFeatureList() {
101: return featureList;
102: }
103:
104: private EventListenerList listenerList = new EventListenerList();
105:
106: public void addPropertyChangeListener(PropertyChangeListener l) {
107: listenerList.add(PropertyChangeListener.class, l);
108: }
109:
110: public void removePropertyChangeListener(PropertyChangeListener l) {
111: listenerList.remove(PropertyChangeListener.class, l);
112: }
113:
114: // ids ...
115:
116: private Map<String, Integer> tokenTypeToID;
117: private Map<Integer, String> idToTokenType;
118: private int tokenTypeCount = 0;
119:
120: public int getTokenID(String tokenType) {
121: if (!tokenTypeToID.containsKey(tokenType))
122: return -1;
123: return tokenTypeToID.get(tokenType);
124: }
125:
126: public int getTokenTypeCount() {
127: return tokenTypeCount;
128: }
129:
130: public String getTokenType(int tokenTypeID) {
131: if (idToTokenType == null)
132: return null;
133: return idToTokenType.get(tokenTypeID);
134: }
135:
136: private Map<String, Integer> ntToNTID;
137: private Map<Integer, String> ntidToNt;
138:
139: public int getNTID(String nt) {
140: if (ntidToNt == null)
141: ntidToNt = new HashMap<Integer, String>();
142: if (ntToNTID == null)
143: ntToNTID = new HashMap<String, Integer>();
144: if (!ntToNTID.containsKey(nt)) {
145: int id = ntToNTID.size();
146: ntToNTID.put(nt, id);
147: ntidToNt.put(id, nt);
148: }
149: return ntToNTID.get(nt);
150: }
151:
152: public int getNTCount() {
153: if (ntToNTID == null)
154: return 0;
155: return ntToNTID.size();
156: }
157:
158: public String getNT(int ntid) {
159: return ntidToNt.get(ntid);
160: }
161:
162: // imports ...
163:
164: private Feature preprocessorImport;
165: private Map<String, Feature> tokenImports = new HashMap<String, Feature>();
166: private List<Language> importedLangauges = new ArrayList<Language>();
167:
168: public Feature getPreprocessorImport() {
169: return preprocessorImport;
170: }
171:
172: public Map<String, Feature> getTokenImports() {
173: return tokenImports;
174: }
175:
176: public List<Language> getImportedLanguages() {
177: return importedLangauges;
178: }
179:
180: void importLanguage(Feature feature) {
181: String mimeType = (String) feature.getValue("mimeType");
182: if (feature.getPattern("start") != null) {
183: //feature.put ("token", Language.EMBEDDING_TOKEN_TYPE_NAME);
184: assert (preprocessorImport == null);
185: preprocessorImport = feature;
186: try {
187: importedLangauges.add(LanguagesManager.getDefault()
188: .getLanguage(mimeType));
189: } catch (LanguageDefinitionNotFoundException ex) {
190: importedLangauges.add(Language.create(mimeType));
191: }
192: return;
193: }
194: if (feature.getValue("state") == null) {
195: String tokenName = feature.getSelector().getAsString();
196: assert (!tokenImports.containsKey(tokenName));
197: tokenImports.put(tokenName, feature);
198: try {
199: importedLangauges.add(LanguagesManager.getDefault()
200: .getLanguage(mimeType));
201: } catch (LanguageDefinitionNotFoundException ex) {
202: importedLangauges.add(Language.create(mimeType));
203: }
204: return;
205: }
206: try {
207: Language language = LanguagesManager.getDefault()
208: .getLanguage(mimeType);
209:
210: String state = (String) feature.getValue("state");
211: String tokenName = feature.getSelector().getAsString();
212:
213: // import tokenTypes
214: //!! Iterator<TokenType> it = language.getTokenTypes ().iterator ();
215: // while (it.hasNext ()) {
216: // TokenType tt = it.next ();
217: // String startState = tt.getStartState ();
218: // Pattern pattern = tt.getPattern ().clonePattern ();
219: // String endState = tt.getEndState ();
220: // if (startState == null || Parser.DEFAULT_STATE.equals (startState))
221: // startState = state;
222: // else
223: // startState = tokenName + '-' + startState;
224: // if (endState == null || Parser.DEFAULT_STATE.equals (endState))
225: // endState = state;
226: // else
227: // endState = tokenName + '-' + endState;
228: // //!!addToken (startState, tt.getType (), pattern, endState, tt.getProperties ());
229: // }
230:
231: // import grammar rues
232: if (language.getAnalyser() != null)
233: try {
234: analyser = LLSyntaxAnalyser.create(this , language
235: .getAnalyser().getRules(), language
236: .getAnalyser().getSkipTokenTypes());
237: } catch (ParseException ex) {
238: ex.printStackTrace();
239: }
240: // import features
241: featureList.importFeatures(language.getFeatureList());
242: importedLangauges.addAll(language.getImportedLanguages());
243: tokenImports.putAll(language.getTokenImports());
244: } catch (LanguageDefinitionNotFoundException ex) {
245: Utils.notify("Editors/" + mimeType + "/language.nbs:", ex);
246: }
247: }
248:
249: // other methods ...........................................................
250:
251: public void read(NBSLanguageReader reader) throws ParseException,
252: IOException {
253: this .reader = reader;
254: read();
255: }
256:
257: private Object INIT_LOCK = new Object();
258:
259: public ASTNode parse(InputStream is) throws IOException,
260: ParseException {
261: synchronized (INIT_LOCK) {
262: if (tokenTypeToID == null) {
263: try {
264: INIT_LOCK.wait();
265: } catch (InterruptedException ex) {
266: }
267: }
268: return super .parse(is);
269: }
270: }
271:
272: public void read() throws ParseException, IOException {
273: try {
274: tokenTypeToID = new HashMap<String, Integer>();
275: idToTokenType = new HashMap<Integer, String>();
276: featureList = new FeatureList();
277: if (!reader.containsTokens()) {
278: org.netbeans.api.lexer.Language lexerLanguage = org.netbeans.api.lexer.Language
279: .find(getMimeType());
280: if (lexerLanguage != null) {
281: Iterator it = lexerLanguage.tokenIds().iterator();
282: while (it.hasNext()) {
283: TokenId tokenId = (TokenId) it.next();
284: int id = tokenId.ordinal();
285: String name = tokenId.name();
286: idToTokenType.put(id, name);
287: tokenTypeToID.put(name, id);
288: tokenTypeCount = Math.max(tokenTypeCount,
289: id + 1);
290: }
291: } else
292: initLexicalStuff(reader.getTokenTypes());
293: } else
294: initLexicalStuff(reader.getTokenTypes());
295:
296: List<Feature> features = reader.getFeatures();
297: Iterator<Feature> it2 = features.iterator();
298: while (it2.hasNext()) {
299: Feature feature = it2.next();
300: if (feature.getFeatureName().equals(IMPORT_FEATURE))
301: importLanguage(feature);
302: featureList.add(feature);
303: }
304: Set<Integer> skipTokenIDs = new HashSet<Integer>();
305: Iterator<Feature> it = featureList.getFeatures("SKIP")
306: .iterator();
307: while (it.hasNext()) {
308: Feature feature = it.next();
309: if (feature.getFeatureName().equals("SKIP")) {
310: skipTokenIDs.add(tokenTypeToID.get(feature
311: .getSelector().toString()));
312: }
313: }
314: List<Rule> rules = reader.getRules(this );
315: analyser = LLSyntaxAnalyser.create(this , rules,
316: skipTokenIDs);
317: fire();
318: synchronized (INIT_LOCK) {
319: INIT_LOCK.notifyAll();
320: }
321: } finally {
322: reader = null;
323: }
324: }
325:
326: private void initLexicalStuff(List<TokenType> tokenTypes) {
327: Iterator<TokenType> it = tokenTypes.iterator();
328: while (it.hasNext()) {
329: TokenType tokenType = it.next();
330: int id = tokenType.getTypeID();
331: String name = tokenType.getType();
332: idToTokenType.put(id, name);
333: tokenTypeToID.put(name, id);
334: tokenTypeCount = Math.max(tokenTypeCount, id + 1);
335: }
336: parser = Parser.create(tokenTypes);
337: }
338:
339: protected void fire() {
340: if (listenerList == null)
341: return;
342: Object[] l = listenerList.getListenerList();
343: PropertyChangeEvent event = null;
344: for (int i = l.length - 2; i >= 0; i -= 2) {
345: if (event == null)
346: event = new PropertyChangeEvent(this , null, null, null);
347: ((PropertyChangeListener) l[i + 1]).propertyChange(event);
348: }
349: }
350:
351: public String toString() {
352: return "LanguageImpl " + mimeType + " (" + hashCode() + ")";
353: }
354: }
|