001: /*
002: * LispTagger.java
003: *
004: * Copyright (C) 1998-2004 Peter Graves
005: * $Id: LispTagger.java,v 1.15 2004/04/11 18:34:51 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: import java.util.ArrayList;
025:
026: public final class LispTagger extends Tagger {
027: // States.
028: private static final int NEUTRAL = 0;
029: private static final int OPEN_PAREN = 1;
030: private static final int DEFINITION = 2;
031:
032: private static final Mode mode = LispMode.getMode();
033:
034: private ArrayList tags;
035:
036: public LispTagger(SystemBuffer buffer) {
037: super (buffer);
038: }
039:
040: public synchronized void run() {
041: tags = new ArrayList();
042: Position pos = new Position(buffer.getFirstLine(), 0);
043: int state = NEUTRAL;
044: String definer = null;
045: while (!pos.atEnd()) {
046: char c = pos.getChar();
047: if (Character.isWhitespace(c)) {
048: pos.skipWhitespace();
049: continue;
050: }
051: if (c == '\\') {
052: // Escape.
053: if (pos.getOffset() < pos.getLineLength() - 1)
054: pos.skip(2);
055: else {
056: Line nextLine = pos.getNextLine();
057: if (nextLine == null)
058: break;
059: pos.moveTo(nextLine, 0);
060: }
061: continue;
062: }
063: if (c == '#' && pos.lookingAt("#|")) {
064: pos.skip(2);
065: skipComment(pos);
066: continue;
067: }
068: if (c == '\"') {
069: pos.skipQuote();
070: continue;
071: }
072: if (c == ';') {
073: // Comment.
074: Line nextLine = pos.getNextLine();
075: if (nextLine == null)
076: break;
077: pos.moveTo(nextLine, 0);
078: continue;
079: }
080: if (c == '(') {
081: if (state == DEFINITION) {
082: if (definer != null) {
083: if (definer.equals("defun")) {
084: Position tokenStart = pos.copy();
085: String name = gatherList(pos);
086: addTag(name, tokenStart, definer);
087: state = NEUTRAL;
088: definer = null;
089: continue;
090: }
091: if (definer.equals("defstruct")) {
092: pos.next();
093: pos.skipWhitespace();
094: c = pos.getChar();
095: if (mode.isIdentifierStart(c)) {
096: Position tokenStart = pos.copy();
097: String token = gatherToken(pos);
098: addTag(token, tokenStart, definer);
099: state = NEUTRAL;
100: definer = null;
101: continue;
102: }
103: }
104: }
105: }
106: state = OPEN_PAREN;
107: pos.next();
108: continue;
109: }
110: if (mode.isIdentifierStart(c)) {
111: if (state == DEFINITION) {
112: Position tokenStart = pos.copy();
113: String token = gatherToken(pos);
114: addTag(token, tokenStart, definer);
115: state = NEUTRAL;
116: definer = null;
117: continue;
118: }
119: if (state == OPEN_PAREN) {
120: String preceding = pos.getLine().substring(0,
121: pos.getOffset()).trim();
122: if (!preceding.equals("(")) {
123: state = NEUTRAL;
124: continue;
125: }
126: String token = gatherToken(pos).toLowerCase();
127: token = LispMode.translateDefiner(token);
128: if (token != null) {
129: state = DEFINITION;
130: definer = token;
131: } else
132: state = NEUTRAL;
133: continue;
134: }
135: skipToken(pos);
136: continue;
137: }
138: state = NEUTRAL;
139: pos.next();
140: }
141: buffer.setTags(tags);
142: }
143:
144: private void addTag(String name, Position pos, String definer) {
145: int type = -1;
146: if (definer.equals("defclass"))
147: type = TAG_CLASS;
148: else if (definer.equals("defconstant"))
149: type = TAG_CONSTANT;
150: else if (definer.equals("defgeneric"))
151: type = TAG_GENERIC_FUNCTION;
152: else if (definer.equals("define-condition"))
153: type = TAG_CONDITION;
154: else if (definer.equals("defmacro"))
155: type = TAG_MACRO;
156: else if (definer.equals("defmethod"))
157: type = TAG_METHOD;
158: else if (definer.equals("defparameter"))
159: type = TAG_PARAMETER;
160: else if (definer.equals("defstruct"))
161: type = TAG_STRUCT;
162: else if (definer.equals("deftype"))
163: type = TAG_TYPE;
164: else if (definer.equals("defun"))
165: type = TAG_DEFUN;
166: else if (definer.equals("defvar"))
167: type = TAG_VAR;
168: else
169: Debug.bug();
170: tags.add(new LispTag(name, pos, type));
171: }
172:
173: // Advances pos past list.
174: private String gatherList(Position pos) {
175: FastStringBuffer sb = new FastStringBuffer();
176: char c = pos.getChar();
177: Debug.bugIf(c != '(');
178: if (pos.next()) {
179: while ((c = pos.getChar()) != ')') {
180: sb.append(c);
181: if (!pos.next())
182: break;
183: }
184: }
185: return sb.toString();
186: }
187:
188: // Advances pos past token.
189: private String gatherToken(Position pos) {
190: FastStringBuffer sb = new FastStringBuffer();
191: char c;
192: while (mode.isIdentifierPart(c = pos.getChar()) || c == ':') {
193: sb.append(c);
194: if (!pos.next())
195: break;
196: }
197: return sb.toString();
198: }
199:
200: // Advances pos past token.
201: private void skipToken(Position pos) {
202: while (mode.isIdentifierPart(pos.getChar())) {
203: if (!pos.next())
204: return;
205: }
206: }
207:
208: private void skipComment(Position pos) {
209: while (!pos.atEnd()) {
210: char c = pos.getChar();
211: if (c == '\\') {
212: // Escape.
213: if (pos.getOffset() < pos.getLineLength() - 1)
214: pos.skip(2);
215: else {
216: Line nextLine = pos.getNextLine();
217: if (nextLine == null)
218: break;
219: pos.moveTo(nextLine, 0);
220: }
221: continue;
222: }
223: if (c == '|' && pos.lookingAt("|#")) {
224: pos.skip(2);
225: return;
226: }
227: pos.next();
228: }
229: }
230: }
|