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-2007 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.lexer.demo;
043:
044: import javax.swing.event.DocumentEvent;
045: import javax.swing.event.DocumentListener;
046: import javax.swing.text.Segment;
047: import javax.swing.text.Document;
048: import javax.swing.text.BadLocationException;
049: import org.netbeans.api.lexer.Token;
050: import org.netbeans.api.lexer.TokenId;
051: import org.netbeans.api.lexer.LexerInput;
052: import org.netbeans.api.lexer.SampleTextMatcher;
053: import org.netbeans.api.lexer.Language;
054: import org.netbeans.api.lexer.Lexer;
055: import org.netbeans.spi.lexer.util.Compatibility;
056: import org.netbeans.spi.lexer.inc.TextTokenUpdater;
057: import org.netbeans.spi.lexer.util.LexerUtilities;
058:
059: /**
060: * Token updater working over a swing document.
061: *
062: * @author Miloslav Metelka
063: * @version 1.00
064: */
065:
066: public class DemoTokenUpdater extends TextTokenUpdater {
067:
068: private Segment seg = new Segment(); // shared segment instance
069:
070: private final Document doc;
071:
072: private final Language language;
073:
074: private final boolean maintainLookbacks;
075:
076: private boolean debugTokenChanges;
077:
078: private Lexer sharedLexer; // shared lexer instance
079:
080: public DemoTokenUpdater(Document doc, Language language) {
081: this (doc, language, true);
082: }
083:
084: public DemoTokenUpdater(Document doc, Language language,
085: boolean maintainLookbacks) {
086: this .doc = doc;
087: this .language = language;
088: this .maintainLookbacks = maintainLookbacks;
089:
090: doc.addDocumentListener(new DocumentListener() {
091: public void insertUpdate(DocumentEvent evt) {
092: if (debugTokenChanges) {
093: try {
094: System.out.println("\nDocument-insert \""
095: + LexerUtilities.toSource((evt
096: .getDocument()).getText(evt
097: .getOffset(), evt.getLength()))
098: + "\"");
099: } catch (BadLocationException e) {
100: e.printStackTrace();
101: }
102: }
103:
104: update(evt.getOffset(), evt.getLength());
105: }
106:
107: public void removeUpdate(DocumentEvent evt) {
108: if (debugTokenChanges) {
109: System.out.println("\nDocument-remove at offset="
110: + evt.getOffset() + ", length="
111: + evt.getLength());
112: }
113:
114: update(evt.getOffset(), -evt.getLength());
115: }
116:
117: public void changedUpdate(DocumentEvent evt) {
118: }
119: });
120: }
121:
122: public boolean getDebugTokenChanges() {
123: return debugTokenChanges;
124: }
125:
126: public void setDebugTokenChanges(boolean debugTokenChanges) {
127: this .debugTokenChanges = debugTokenChanges;
128: }
129:
130: protected final Document getDocument() {
131: return doc;
132: }
133:
134: protected final Language getLanguage() {
135: return language;
136: }
137:
138: public char textCharAt(int index) {
139: synchronized (seg) {
140: try {
141: doc.getText(index, 1, seg);
142: return seg.array[seg.offset];
143:
144: } catch (BadLocationException e) {
145: throw new IllegalStateException(e.toString());
146: }
147: }
148: }
149:
150: public int textLength() {
151: return doc.getLength();
152: }
153:
154: private String getDocumentText(int offset, int length) {
155: try {
156: return doc.getText(offset, length);
157: } catch (BadLocationException e) {
158: throw new IllegalStateException(e.getMessage());
159: }
160: }
161:
162: protected Token createToken(TokenId id, int index, int length) {
163: String sampleText = null;
164: if (Compatibility.charSequenceExists()) {
165: SampleTextMatcher matcher = id.getSampleTextMatcher();
166: if (matcher != null) {
167: /* The recognizedText would not be a string
168: * in the normal applications. It would be
169: * a custom char sequence reused for every
170: * recognized token. Here it's string
171: * to simplify the code.
172: */
173: CharSequence recognizedText = (CharSequence) (Object) getDocumentText(
174: index, length); // 1.3 compilability
175: sampleText = matcher.match(recognizedText);
176: }
177: }
178:
179: Token token;
180: if (sampleText != null) {
181: token = new DemoSampleToken(id, sampleText);
182: } else {
183: token = new DemoToken(this , id, index, length);
184: }
185:
186: return token;
187: }
188:
189: protected Lexer createLexer() {
190: if (sharedLexer == null) {
191: sharedLexer = language.createLexer();
192: }
193:
194: return sharedLexer;
195: }
196:
197: protected void add(Token token, int lookahead, Object state) {
198: add(token);
199:
200: if (token instanceof DemoSampleToken) {
201: DemoSampleToken dft = (DemoSampleToken) token;
202: dft.setLookahead(lookahead);
203: dft.setState(state);
204: } else {
205: DemoToken dt = (DemoToken) token;
206: dt.setLookahead(lookahead);
207: dt.setState(state);
208: }
209:
210: if (debugTokenChanges) {
211: System.out.println("Added token: [" + (getNextIndex() - 1)
212: + "]=" + tokenToString(token, false));
213: }
214: }
215:
216: protected void remove() {
217: if (debugTokenChanges) {
218: System.out.println("Removed token at index="
219: + (getNextIndex() - 1));
220: }
221:
222: super .remove();
223: }
224:
225: public int getLookahead() {
226: Token token = getToken(getValidPreviousIndex());
227: return (token instanceof DemoSampleToken) ? ((DemoSampleToken) token)
228: .getLookahead()
229: : ((DemoToken) token).getLookahead();
230: }
231:
232: public Object getState() {
233: Token token = getToken(getValidPreviousIndex());
234: return (token instanceof DemoSampleToken) ? ((DemoSampleToken) token)
235: .getState()
236: : ((DemoToken) token).getState();
237: }
238:
239: public int getLookback() {
240: if (maintainLookbacks) {
241: Token token = getToken(getValidPreviousIndex());
242: return (token instanceof DemoSampleToken) ? ((DemoSampleToken) token)
243: .getLookback()
244: : ((DemoToken) token).getLookback();
245:
246: } else { // do not maintain the lookbacks
247: return -1;
248: }
249: }
250:
251: protected void setLookback(int lookback) {
252: if (maintainLookbacks) {
253: Token token = getToken(getValidPreviousIndex());
254: if (token instanceof DemoSampleToken) {
255: ((DemoSampleToken) token).setLookback(lookback);
256: } else {
257: ((DemoToken) token).setLookback(lookback);
258: }
259: }
260: }
261:
262: public boolean hasNext() {
263: return super .hasNext();
264: }
265:
266: public Token next() {
267: return super .next();
268: }
269:
270: public int relocate(int index) {
271: return super .relocate(index);
272: }
273:
274: public String tokenToString(Token token, boolean extraInfo) {
275: StringBuffer sb = new StringBuffer();
276:
277: int length = org.netbeans.spi.lexer.util.Compatibility
278: .getLength(token);
279: String text = org.netbeans.spi.lexer.util.Compatibility
280: .toString(token);
281: sb.append("\""
282: + org.netbeans.spi.lexer.util.LexerUtilities
283: .toSource(text) + "\", " + token.getId());
284:
285: if (token instanceof DemoToken) {
286: DemoToken dt = (DemoToken) token;
287:
288: sb.append(", off=");
289: sb.append(getOffset(dt.getRawOffset()));
290:
291: sb.append(", type=regular");
292: if (extraInfo) {
293: sb.append(", la=" + dt.getLookahead() + ", lb="
294: + dt.getLookback() + ", st=" + dt.getState());
295: }
296:
297: } else {
298: DemoSampleToken dft = (DemoSampleToken) token;
299: sb.append(", type=sample");
300: if (extraInfo) {
301: sb.append(", la=" + dft.getLookahead() + ", lb="
302: + dft.getLookback() + ", st=" + dft.getState());
303: }
304: }
305:
306: return sb.toString();
307: }
308:
309: public String allTokensToString() {
310: StringBuffer sb = new StringBuffer();
311: int cnt = getTokenCount();
312: sb.append("Dump of tokens (tokenCount=" + cnt
313: + ") in token updater:\n");
314: int offset = 0;
315: try {
316: for (int i = 0; i < cnt; i++) {
317: Token t = getToken(i);
318: int length = org.netbeans.spi.lexer.util.Compatibility
319: .getLength(t);
320: String text = org.netbeans.spi.lexer.util.Compatibility
321: .toString(t);
322: sb.append("["
323: + i
324: + "] \""
325: + org.netbeans.spi.lexer.util.LexerUtilities
326: .toSource(text) + "\", " + t.getId()
327: + ", off=" + offset);
328:
329: if (t instanceof DemoToken) {
330: DemoToken dt = (DemoToken) t;
331:
332: if (getOffset(dt.getRawOffset()) != offset) {
333: throw new IllegalStateException(
334: "offsets differ");
335: }
336:
337: sb.append(", type=regular" + ", la="
338: + dt.getLookahead() + ", lb="
339: + dt.getLookback() + ", st="
340: + dt.getState() + "\n");
341:
342: } else {
343: DemoSampleToken dft = (DemoSampleToken) t;
344: sb.append(", type=sample" + ", la="
345: + dft.getLookahead() + ", lb="
346: + dft.getLookback() + ", st="
347: + dft.getState() + "\n");
348: }
349:
350: offset += length;
351: }
352: } catch (RuntimeException e) {
353: System.err.println(sb.toString());
354: throw e;
355: }
356:
357: return sb.toString();
358: }
359:
360: }
|