001: /*
002: * LispString.java
003: *
004: * Copyright (C) 2002-2003 Peter Graves
005: * $Id: LispString.java,v 1.7 2003/11/15 11:03:30 beedlem 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.lisp;
023:
024: public final class LispString extends AbstractVector {
025: private char[] array;
026:
027: public LispString(LispCharacter c) {
028: array = new char[1];
029: array[0] = c.getValue();
030: }
031:
032: public LispString(char c) {
033: array = new char[1];
034: array[0] = c;
035: }
036:
037: public LispString(int length) {
038: array = new char[length];
039: }
040:
041: public LispString(String s) {
042: array = s.toCharArray();
043: }
044:
045: public char[] chars() {
046: return array;
047: }
048:
049: // Used by jvm compiler.
050: public static LispString getInstance(String s) {
051: return new LispString(s);
052: }
053:
054: public LispObject typeOf() {
055: return Symbol.STRING;
056: }
057:
058: public LispClass classOf() {
059: return BuiltInClass.STRING;
060: }
061:
062: public LispObject typep(LispObject type) throws ConditionThrowable {
063: if (type instanceof Symbol) {
064: if (type == Symbol.STRING)
065: return T;
066: if (type == Symbol.BASE_STRING)
067: return T;
068: if (type == Symbol.SIMPLE_STRING
069: || type == Symbol.SIMPLE_BASE_STRING)
070: return fillPointer < 0 ? T : NIL;
071: }
072: if (type == BuiltInClass.STRING)
073: return T;
074: return super .typep(type);
075: }
076:
077: public LispObject STRINGP() {
078: return T;
079: }
080:
081: public LispObject SIMPLE_STRING_P() {
082: return fillPointer < 0 ? T : NIL;
083: }
084:
085: public LispObject getElementType() {
086: return Symbol.CHARACTER;
087: }
088:
089: public boolean isSimpleVector() {
090: return false;
091: }
092:
093: public boolean equal(LispObject obj) {
094: if (this == obj)
095: return true;
096: if (obj instanceof LispString) {
097: LispString string = (LispString) obj;
098: if (string.length() != length())
099: return false;
100: for (int i = length(); i-- > 0;)
101: if (string.array[i] != array[i])
102: return false;
103: return true;
104: }
105: return false;
106: }
107:
108: public boolean equalp(LispObject obj) throws ConditionThrowable {
109: if (this == obj)
110: return true;
111: if (obj instanceof LispString) {
112: LispString string = (LispString) obj;
113: if (string.length() != length())
114: return false;
115: for (int i = length(); i-- > 0;) {
116: if (string.array[i] != array[i]) {
117: if (Utilities.toLowerCase(string.array[i]) != Utilities
118: .toLowerCase(array[i]))
119: return false;
120: }
121: }
122: return true;
123: }
124: if (obj instanceof AbstractArray)
125: return obj.equalp(this );
126: return false;
127: }
128:
129: public LispObject subseq(int start, int end)
130: throws ConditionThrowable {
131: LispString s = new LispString(end - start);
132: int i = start, j = 0;
133: while (i < end)
134: s.array[j++] = array[i++];
135: return s;
136: }
137:
138: public void fill(LispObject obj) throws ConditionThrowable {
139: fill(LispCharacter.getValue(obj));
140: }
141:
142: public void fill(char c) {
143: for (int i = array.length; i-- > 0;)
144: array[i] = c;
145: }
146:
147: public void shrink(int n) throws ConditionThrowable {
148: if (n < array.length) {
149: char[] newArray = new char[n];
150: System.arraycopy(array, 0, newArray, 0, n);
151: array = newArray;
152: return;
153: }
154: if (n == array.length)
155: return;
156: throw new ConditionThrowable(new LispError());
157: }
158:
159: public LispObject reverse() throws ConditionThrowable {
160: int length = length();
161: LispString result = new LispString(length);
162: int i, j;
163: for (i = 0, j = length - 1; i < length; i++, j--)
164: result.array[i] = array[j];
165: return result;
166: }
167:
168: public LispObject nreverse() throws ConditionThrowable {
169: int i = 0;
170: int j = length() - 1;
171: while (i < j) {
172: char temp = array[i];
173: array[i] = array[j];
174: array[j] = temp;
175: ++i;
176: --j;
177: }
178: return this ;
179: }
180:
181: public LispObject getRowMajor(int index) throws ConditionThrowable {
182: try {
183: return LispCharacter.getInstance(array[index]);
184: } catch (ArrayIndexOutOfBoundsException e) {
185: badIndex(index, array.length);
186: return NIL; // Not reached.
187: }
188: }
189:
190: public void setRowMajor(int index, LispObject newValue)
191: throws ConditionThrowable {
192: try {
193: array[index] = LispCharacter.getValue(newValue);
194: } catch (ArrayIndexOutOfBoundsException e) {
195: badIndex(index, array.length);
196: }
197: }
198:
199: public LispObject get(int index) throws ConditionThrowable {
200: try {
201: return LispCharacter.getInstance(array[index]);
202: } catch (ArrayIndexOutOfBoundsException e) {
203: badIndex(index, array.length);
204: return NIL; // Not reached.
205: }
206: }
207:
208: public void set(int index, LispObject newValue)
209: throws ConditionThrowable {
210: try {
211: array[index] = LispCharacter.getValue(newValue);
212: } catch (ArrayIndexOutOfBoundsException e) {
213: badIndex(index, array.length);
214: }
215: }
216:
217: public void set(int index, char c) {
218: array[index] = c;
219: }
220:
221: public static String getValue(LispObject obj)
222: throws ConditionThrowable {
223: try {
224: return ((LispString) obj).getValue();
225: } catch (ClassCastException e) {
226: throw new ConditionThrowable(new TypeError(obj, "string"));
227: }
228: }
229:
230: public final String getValue() {
231: return new String(array);
232: }
233:
234: public Object javaInstance() {
235: return new String(array);
236: }
237:
238: public final int capacity() {
239: return array.length;
240: }
241:
242: public final void ensureCapacity(int minCapacity) {
243: if (array.length < minCapacity) {
244: char[] newArray = new char[minCapacity];
245: System.arraycopy(array, 0, newArray, 0, array.length);
246: array = newArray;
247: }
248: }
249:
250: public final int length() {
251: return fillPointer >= 0 ? fillPointer : array.length;
252: }
253:
254: public LispObject elt(int index) throws ConditionThrowable {
255: int limit = fillPointer >= 0 ? fillPointer : array.length;
256: if (index < 0 || index >= limit)
257: badIndex(index, limit);
258: return LispCharacter.getInstance(array[index]);
259: }
260:
261: // Ignores fill pointer.
262: public LispObject AREF(LispObject index) throws ConditionThrowable {
263: try {
264: return LispCharacter.getInstance(array[Fixnum
265: .getValue(index)]);
266: } catch (ArrayIndexOutOfBoundsException e) {
267: badIndex(Fixnum.getValue(index), array.length);
268: return NIL; // Not reached.
269: }
270: }
271:
272: public LispObject remove(LispObject item) throws ConditionThrowable {
273: throw new ConditionThrowable(new LispError("not implemented"));
274: }
275:
276: private int cachedHashCode;
277:
278: public int hashCode() {
279: if (cachedHashCode != 0)
280: return cachedHashCode;
281: int hashCode = 0;
282: final int limit = array.length;
283: for (int i = 0; i < limit; i++)
284: hashCode = hashCode * 31 + array[i];
285: return cachedHashCode = hashCode;
286: }
287:
288: public final String toString() {
289: if (_PRINT_ESCAPE_.symbolValueNoThrow() != NIL) {
290: StringBuffer sb = new StringBuffer();
291: sb.append('"');
292: final int limit = fillPointer >= 0 ? fillPointer
293: : array.length;
294: for (int i = 0; i < limit; i++) {
295: char c = array[i];
296: if (c == '\"')
297: sb.append('\\');
298: sb.append(c);
299: }
300: sb.append('"');
301: return sb.toString();
302: } else
303: return getValue();
304: }
305:
306: // ### %make-string
307: // %make-string size initial-element element-type => string
308: // Returns a simple string.
309: private static final Primitive3 _MAKE_STRING = new Primitive3(
310: "%make-string", PACKAGE_SYS, false) {
311: public LispObject execute(LispObject size,
312: LispObject initialElement, LispObject elementType)
313: throws ConditionThrowable {
314: final int n = Fixnum.getValue(size);
315: final int limit = Fixnum
316: .getValue(Symbol.ARRAY_DIMENSION_LIMIT
317: .getSymbolValue());
318: if (n < 0 || n >= limit) {
319: StringBuffer sb = new StringBuffer();
320: sb.append("the size specified for this string (");
321: sb.append(n);
322: sb.append(')');
323: if (n >= limit) {
324: sb.append(" is >= ARRAY-DIMENSION-LIMIT (");
325: sb.append(limit);
326: sb.append(')');
327: } else
328: sb.append(" is negative");
329: throw new ConditionThrowable(new LispError(sb
330: .toString()));
331: }
332: // Ignore elementType.
333: LispString string = new LispString(n);
334: if (initialElement != NIL) {
335: // Initial element was specified.
336: char c = checkCharacter(initialElement).getValue();
337: string.fill(c);
338: }
339: return string;
340: }
341: };
342:
343: private static final Primitive2 CHAR = new Primitive2("char") {
344: public LispObject execute(LispObject first, LispObject second)
345: throws ConditionThrowable {
346: return checkString(first).get(Fixnum.getInt(second));
347: }
348: };
349:
350: private static final Primitive3 _SET_CHAR = new Primitive3(
351: "%set-char", PACKAGE_SYS, false) {
352: public LispObject execute(LispObject first, LispObject second,
353: LispObject third) throws ConditionThrowable {
354: checkString(first).set(Fixnum.getInt(second),
355: checkCharacter(third));
356: return third;
357: }
358: };
359:
360: private static final Primitive2 SCHAR = new Primitive2("schar") {
361: public LispObject execute(LispObject first, LispObject second)
362: throws ConditionThrowable {
363: return checkString(first).get(Fixnum.getInt(second));
364: }
365: };
366:
367: private static final Primitive3 _SET_SCHAR = new Primitive3(
368: "%set-schar", PACKAGE_SYS, false) {
369: public LispObject execute(LispObject first, LispObject second,
370: LispObject third) throws ConditionThrowable {
371: checkString(first).set(Fixnum.getInt(second),
372: checkCharacter(third));
373: return third;
374: }
375: };
376:
377: private static final Primitive3 STRING_POSITION = new Primitive3(
378: "string-position", PACKAGE_EXT, true) {
379: public LispObject execute(LispObject first, LispObject second,
380: LispObject third) throws ConditionThrowable {
381: char c = LispCharacter.getValue(first);
382: LispString string = checkString(second);
383: int start = Fixnum.getValue(third);
384: char[] chars = string.chars();
385: for (int i = start, limit = chars.length; i < limit; i++) {
386: if (chars[i] == c)
387: return number(i);
388: }
389: return NIL;
390: }
391: };
392: }
|