001: // Copyright (c) 2001 Per M.A. Bothner
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.lispexpr;
005:
006: import gnu.text.*;
007: import gnu.mapping.InPort;
008: import gnu.mapping.Values;
009: import gnu.mapping.Procedure;
010: import gnu.bytecode.Type;
011: import gnu.lists.*;
012:
013: public class ReaderDispatchMisc extends ReadTableEntry {
014: /** A code which specifies which particular reader-action to perform.
015: * The code is one the CommonLisp or Scheme '#' reader characters.
016: * For example, if code=='x' then read a hexadecimal integer.
017: * If code==-1, perform the standard action for the character read. */
018: protected int code;
019:
020: private static ReaderDispatchMisc instance = new ReaderDispatchMisc();
021:
022: public static ReaderDispatchMisc getInstance() {
023: return instance;
024: }
025:
026: public ReaderDispatchMisc() {
027: code = -1;
028: }
029:
030: public ReaderDispatchMisc(int code) {
031: this .code = code;
032: }
033:
034: public Object read(Lexer in, int ch, int count)
035: throws java.io.IOException, SyntaxException {
036: LispReader reader = (LispReader) in;
037: char saveReadState = '\0';
038: LineBufferedReader port;
039: int length;
040: String name;
041: if (code >= 0)
042: ch = code;
043: switch (ch) {
044: case ':':
045: // Handle Guile-style keyword syntax: '#:KEYWORD'
046: // Note this conflicts with Common Lisp uninterned symbols. FIXME
047: int startPos = reader.tokenBufferLength;
048: reader
049: .readToken(reader.read(), 'P', ReadTable
050: .getCurrent());
051: length = reader.tokenBufferLength - startPos;
052: name = new String(reader.tokenBuffer, startPos, length);
053: reader.tokenBufferLength = startPos;
054: return gnu.expr.Keyword.make(name.intern());
055: case '\\':
056: return LispReader.readCharacter(reader);
057: case '!':
058: return LispReader.readSpecial(reader);
059: case 'T':
060: return Boolean.TRUE;
061: case 'F':
062: ch = in.peek();
063: if (Character.isDigit((char) ch))
064: return LispReader.readSimpleVector(reader, 'F');
065: return Boolean.FALSE;
066: case 'S':
067: case 'U':
068: return LispReader.readSimpleVector(reader, (char) ch);
069: case 'R':
070: if (count > 36) {
071: in.error("the radix " + count
072: + " is too big (max is 36)");
073: count = 36;
074: }
075: return LispReader.readNumberWithRadix(0, reader, count);
076: case 'X':
077: return LispReader.readNumberWithRadix(0, reader, 16);
078: case 'D':
079: return LispReader.readNumberWithRadix(0, reader, 10);
080: case 'O':
081: return LispReader.readNumberWithRadix(0, reader, 8);
082: case 'B':
083: return LispReader.readNumberWithRadix(0, reader, 2);
084: case 'I':
085: case 'E':
086: reader.tokenBufferAppend('#');
087: reader.tokenBufferAppend(ch);
088: return LispReader.readNumberWithRadix(2, reader, 0);
089: case '|':
090: port = reader.getPort();
091: if (port instanceof InPort) {
092: saveReadState = ((InPort) port).readState;
093: ((InPort) port).readState = '|';
094: }
095: try {
096: reader.readNestedComment('#', '|');
097: } finally {
098: if (port instanceof InPort)
099: ((InPort) port).readState = saveReadState;
100: }
101: return Values.empty;
102: case ',':
103: port = reader.getPort();
104: Object list;
105: if (port.peek() == '('
106: && ((length = LList.listLength(list = reader
107: .readObject(), false)) > 0)
108: && ((Pair) list).car instanceof String) {
109: name = (String) ((Pair) list).car;
110: Object proc = ReadTable.getCurrent()
111: .getReaderCtor(name);
112: if (proc == null)
113: in.error("unknown reader constructor " + name);
114: else if (!(proc instanceof Procedure || proc instanceof Type))
115: in
116: .error("reader constructor must be procedure or type name");
117: else {
118: length--; // Subtract 1 for the constructor name.
119: int parg = proc instanceof Type ? 1 : 0;
120: Object[] args = new Object[parg + length];
121: Object argList = ((Pair) list).cdr;
122: for (int i = 0; i < length; i++) {
123: Pair pair = (Pair) argList;
124: args[parg + i] = pair.car;
125: argList = pair.cdr;
126: }
127: try {
128: if (parg > 0) {
129: args[0] = proc;
130: return gnu.kawa.reflect.Invoke.make
131: .applyN(args);
132: }
133: return ((Procedure) proc).applyN(args);
134: } catch (Throwable ex) {
135: in.error("caught " + ex
136: + " applying reader constructor "
137: + name);
138: }
139: }
140: } else
141: in
142: .error("a non-empty list starting with a symbol must follow #,");
143: return Boolean.FALSE;
144: default:
145: in.error("An invalid #-construct was read.");
146: return Values.empty;
147: }
148: }
149: }
|