001: /*
002: * SchemeFormatter.java
003: *
004: * Copyright (C) 1998-2002 Peter Graves
005: * $Id: SchemeFormatter.java,v 1.1.1.1 2002/09/24 16:09:14 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: public final class SchemeFormatter extends Formatter {
025: // Formats.
026: private static final int SCHEME_FORMAT_TEXT = 0;
027: private static final int SCHEME_FORMAT_COMMENT = 1;
028: private static final int SCHEME_FORMAT_STRING = 2;
029: private static final int SCHEME_FORMAT_KEYWORD = 3;
030: private static final int SCHEME_FORMAT_FUNCTION = 4;
031: private static final int SCHEME_FORMAT_NUMBER = 5;
032:
033: private FastStringBuffer sb = new FastStringBuffer();
034: private int tokStart;
035:
036: public SchemeFormatter(Buffer buffer) {
037: this .buffer = buffer;
038: }
039:
040: private void endToken(int state) {
041: if (sb.length() > 0) {
042: int format = -1;
043: switch (state) {
044: case STATE_NEUTRAL:
045: break;
046: case STATE_QUOTE:
047: format = SCHEME_FORMAT_STRING;
048: break;
049: case STATE_IDENTIFIER:
050: break;
051: case STATE_COMMENT:
052: format = SCHEME_FORMAT_COMMENT;
053: break;
054: case STATE_NUMBER:
055: case STATE_HEXNUMBER:
056: format = SCHEME_FORMAT_NUMBER;
057: break;
058: }
059: addSegment(sb.toString(), format);
060: tokStart += sb.length();
061: sb.setLength(0);
062: }
063: }
064:
065: private void parseLine(String text, int state) {
066: if (Editor.tabsAreVisible())
067: text = Utilities
068: .makeTabsVisible(text, buffer.getTabWidth());
069: else
070: text = Utilities.detab(text, buffer.getTabWidth());
071: clearSegmentList();
072: sb.setLength(0);
073: int i = 0;
074: tokStart = 0;
075: final int limit = text.length();
076: // Skip whitespace at start of line.
077: while (i < limit) {
078: char c = text.charAt(i);
079: if (Character.isWhitespace(c)) {
080: sb.append(c);
081: ++i;
082: } else {
083: endToken(state);
084: break;
085: }
086: }
087: while (i < limit) {
088: char c = text.charAt(i);
089: if (c == '\\' && i < limit - 1) {
090: sb.append(c);
091: sb.append(text.charAt(++i));
092: ++i;
093: continue;
094: }
095: if (state == STATE_COMMENT) {
096: if (c == '|' && i < limit - 1) {
097: c = text.charAt(i + 1);
098: if (c == '#') {
099: sb.append("|#");
100: endToken(state);
101: state = STATE_NEUTRAL;
102: i += 2;
103: continue;
104: }
105: }
106: sb.append(c);
107: ++i;
108: continue;
109: }
110: if (state == STATE_QUOTE) {
111: sb.append(c);
112: if (c == '"') {
113: endToken(state);
114: state = STATE_NEUTRAL;
115: }
116: ++i;
117: continue;
118: }
119: // Reaching here, we're not in a quoted string.
120: if (c == '"') {
121: endToken(state);
122: sb.append(c);
123: state = STATE_QUOTE;
124: ++i;
125: continue;
126: }
127: if (c == ';') {
128: endToken(state);
129: state = STATE_COMMENT;
130: sb.append(text.substring(i));
131: endToken(state);
132: return;
133: }
134: if (c == '#' && i < limit - 1) {
135: if (text.charAt(i + 1) == '|') {
136: endToken(state);
137: state = STATE_COMMENT;
138: sb.append("#|");
139: i += 2;
140: continue;
141: }
142: }
143: if (state == STATE_IDENTIFIER) {
144: if (buffer.getMode().isIdentifierPart(c))
145: sb.append(c);
146: else {
147: endToken(state);
148: sb.append(c);
149: state = STATE_NEUTRAL;
150: }
151: ++i;
152: continue;
153: }
154: if (state == STATE_NUMBER) {
155: if (Character.isDigit(c))
156: sb.append(c);
157: else if (c == 'u' || c == 'U' || c == 'l' || c == 'L')
158: sb.append(c); // Valid suffix.
159: else if (sb.length() == 1 && c == 'x' || c == 'X') {
160: sb.append(c);
161: state = STATE_HEXNUMBER;
162: } else {
163: endToken(state);
164: sb.append(c);
165: if (Character.isJavaIdentifierStart(c))
166: state = STATE_IDENTIFIER;
167: else
168: state = STATE_NEUTRAL;
169: }
170: ++i;
171: continue;
172: }
173: if (state == STATE_HEXNUMBER) {
174: if (Character.isDigit(c))
175: sb.append(c);
176: else if ((c >= 'a' && c <= 'f')
177: || (c >= 'A' && c <= 'F'))
178: sb.append(c);
179: else if (c == 'u' || c == 'U' || c == 'l' || c == 'L')
180: sb.append(c); // Valid suffix.
181: else {
182: endToken(state);
183: sb.append(c);
184: if (Character.isJavaIdentifierStart(c))
185: state = STATE_IDENTIFIER;
186: else
187: state = STATE_NEUTRAL;
188: }
189: ++i;
190: continue;
191: }
192: if (state == STATE_NEUTRAL) {
193: if (buffer.mode.isIdentifierStart(c)) {
194: endToken(state);
195: sb.append(c);
196: state = STATE_IDENTIFIER;
197: } else if (Character.isDigit(c)) {
198: endToken(state);
199: sb.append(c);
200: state = STATE_NUMBER;
201: } else
202: // Still neutral...
203: sb.append(c);
204: }
205: ++i;
206: }
207: endToken(state);
208: }
209:
210: public LineSegmentList formatLine(Line line) {
211: if (line == null) {
212: clearSegmentList();
213: addSegment("", SCHEME_FORMAT_TEXT);
214: return segmentList;
215: }
216: parseLine(line.getText(), line.flags());
217: final int size = segmentList.size();
218: for (int i = 0; i < size; i++) {
219: LineSegment segment = segmentList.getSegment(i);
220: if (segment.getFormat() >= 0)
221: continue;
222: String token = segment.getText();
223: if (isKeyword(token))
224: segment.setFormat(SCHEME_FORMAT_KEYWORD);
225: else {
226: boolean isFunction = false;
227: if (i >= 2) {
228: LineSegment prevSegment = segmentList
229: .getSegment(i - 2);
230: String prevToken = prevSegment.getText();
231: String trim = prevToken.trim();
232: if (trim.equals("define"))
233: isFunction = true;
234: }
235: segment.setFormat(isFunction ? SCHEME_FORMAT_FUNCTION
236: : SCHEME_FORMAT_TEXT);
237: }
238: }
239: return segmentList;
240: }
241:
242: public boolean parseBuffer() {
243: int state = STATE_NEUTRAL;
244: boolean changed = false;
245: Line line = buffer.getFirstLine();
246: while (line != null) {
247: int oldflags = line.flags();
248: if (state != oldflags) {
249: line.setFlags(state);
250: changed = true;
251: }
252: final int limit = line.length();
253: for (int i = 0; i < limit; i++) {
254: char c = line.charAt(i);
255: if (c == '\\' && i < limit - 1) {
256: // Escape.
257: ++i;
258: continue;
259: }
260: if (state == STATE_COMMENT) {
261: if (c == '|' && i < limit - 1
262: && line.charAt(i + 1) == '#') {
263: ++i;
264: state = STATE_NEUTRAL;
265: }
266: continue;
267: }
268: if (state == STATE_QUOTE) {
269: if (c == '"')
270: state = STATE_NEUTRAL;
271: continue;
272: }
273: // Not in comment or quoted string.
274: if (c == ';') {
275: // Single-line comment beginning. Ignore rest of line.
276: break;
277: }
278: if (c == '#') {
279: if (i < limit - 1 && line.charAt(i + 1) == '|') {
280: state = STATE_COMMENT;
281: ++i;
282: }
283: continue;
284: }
285: if (c == '"')
286: state = STATE_QUOTE;
287: }
288: line = line.next();
289: }
290: buffer.setNeedsParsing(false);
291: return changed;
292: }
293:
294: public FormatTable getFormatTable() {
295: if (formatTable == null) {
296: formatTable = new FormatTable("SchemeMode");
297: formatTable.addEntryFromPrefs(SCHEME_FORMAT_TEXT, "text");
298: formatTable.addEntryFromPrefs(SCHEME_FORMAT_COMMENT,
299: "comment");
300: formatTable.addEntryFromPrefs(SCHEME_FORMAT_STRING,
301: "string");
302: formatTable.addEntryFromPrefs(SCHEME_FORMAT_KEYWORD,
303: "keyword");
304: formatTable.addEntryFromPrefs(SCHEME_FORMAT_FUNCTION,
305: "function");
306: formatTable.addEntryFromPrefs(SCHEME_FORMAT_NUMBER,
307: "number");
308: }
309: return formatTable;
310: }
311: }
|