001: // Copyright (c) 2001, 2003, 2006 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.kawa.util.RangeTable;
007: import gnu.mapping.*;
008: import gnu.expr.Language;
009: import gnu.kawa.reflect.StaticFieldLocation;
010:
011: public class ReadTable extends RangeTable {
012: /** Kinds of characters. */
013: public static final int ILLEGAL = 0;
014: public static final int WHITESPACE = 1;
015: public static final int CONSTITUENT = 2;
016: public static final int SINGLE_ESCAPE = 3;
017: public static final int MULTIPLE_ESCAPE = 4;
018: public static final int TERMINATING_MACRO = 5;
019: public static final int NON_TERMINATING_MACRO = 6;
020:
021: /** Default value to pass to setBracketMode() unless overridden. */
022: public static int defaultBracketMode = -1;
023:
024: /** A character such that PreOpWord -> ($lookup$ Pre 'Word), if > 0. */
025: public char postfixLookupOperator = (char) (-1);
026:
027: static final ThreadLocation current = new ThreadLocation(
028: "read-table");
029:
030: public ReadTable() {
031: }
032:
033: public void initialize() {
034: ReadTableEntry entry;
035: entry = ReadTableEntry.getWhitespaceInstance();
036: set(' ', entry);
037: set('\t', entry);
038: set('\n', entry);
039: set('\r', entry);
040: set('\f', entry);
041: //set('\v', entry);
042: set('|', ReadTableEntry.getMultipleEscapeInstance());
043: set('\\', ReadTableEntry.getSingleEscapeInstance());
044: set('0', '9', ReadTableEntry.getDigitInstance());
045: entry = ReadTableEntry.getConstituentInstance();
046: set('a', 'z', entry);
047: set('A', 'Z', entry);
048: set('!', entry);
049: set('$', entry);
050: set('%', entry);
051: set('&', entry);
052: set('*', entry);
053: set('+', entry);
054: set('-', entry);
055: set('.', entry);
056: set('/', entry);
057: set(':', entry);
058: set('=', entry);
059: set('>', entry);
060: set('?', entry);
061: set('@', entry);
062: set('^', entry);
063: set('_', entry);
064: set('{', entry);
065: set('}', entry);
066: set('~', entry);
067: set('\177', entry);
068: set('\b', entry);
069: set('\"', new ReaderString());
070: set('#', ReaderDispatch.create());
071: set(';', ReaderIgnoreRestOfLine.getInstance());
072: set('(', ReaderParens.getInstance('(', ')'));
073:
074: set('\'', new ReaderQuote(LispLanguage.quote_sym));
075: set('`', new ReaderQuote(LispLanguage.quasiquote_sym));
076: set(',', new ReaderQuote(LispLanguage.unquote_sym, '@',
077: LispLanguage.unquotesplicing_sym));
078:
079: setBracketMode(); // Sets the entries for '[', ']', and '<'.
080:
081: }
082:
083: /** Create a new ReadTable and initialize it appropriately for Common Lisp. */
084: public static ReadTable createInitial() {
085: ReadTable tab = new ReadTable();
086: tab.initialize();
087: return tab;
088: }
089:
090: /** Specify how '[' and ']' (and '<') are handled.
091: * The value -1 means that '[' and ']' are plain token constituents.
092: * The value 0 means that '[' and ']' are equivalent to '(' and ')'.
093: * The value 1 means that '[' and ']' are equivalent to '(' and ')', except
094: * within a token starting with '<', in which case they are constituents.
095: * This is so '[' is non-terminating when reading say '<char[]>'
096: */
097: public void setBracketMode(int mode) {
098: if (mode <= 0) {
099: ReadTableEntry token = ReadTableEntry
100: .getConstituentInstance();
101: set('<', token);
102: if (mode < 0) {
103: set('[', token);
104: set(']', token);
105: }
106: } else
107: set('<', new ReaderTypespec());
108: if (mode >= 0) {
109: set('[', ReaderParens.getInstance('[', ']'));
110: remove(']');
111: }
112: }
113:
114: /** Specify how '[' and ']' are handled.
115: * Overless overridden, uses defaultBracketMode. */
116: public void setBracketMode() {
117: setBracketMode(defaultBracketMode);
118: }
119:
120: /** A table mapping constructor tags to functions, as in SRFI-10. */
121: Environment ctorTable = null;
122:
123: void initCtorTable() {
124: if (ctorTable == null)
125: ctorTable = Environment.make();
126: }
127:
128: /** Add a mapping for a SRFI-10 constructor tag. */
129: public synchronized void putReaderCtor(String key, Procedure proc) {
130: initCtorTable();
131: ctorTable.put(key, proc);
132: }
133:
134: /** Map a SRFI-10 constructor tag to Procedure-valued lazy field */
135: public synchronized void putReaderCtorFld(String key, String cname,
136: String fname) {
137: initCtorTable();
138: Symbol symbol = ctorTable.getSymbol(key);
139: StaticFieldLocation.define(ctorTable, symbol, null, cname,
140: fname);
141: }
142:
143: /** Resolve a SRFI-10 constructor tags to a functions. */
144: public synchronized Object getReaderCtor(String key) {
145: initCtorTable();
146: return ctorTable.get(key, null);
147: }
148:
149: public static ReadTable getCurrent() {
150: ReadTable table = (ReadTable) current.get(null);
151: if (table == null) {
152: Language language = Language.getDefaultLanguage();
153: if (language instanceof LispLanguage)
154: table = ((LispLanguage) language).defaultReadTable;
155: else
156: table = ReadTable.createInitial();
157: current.set(table);
158: }
159: return table;
160: }
161:
162: public static void setCurrent(ReadTable rt) {
163: current.set(rt);
164: }
165:
166: public ReadTableEntry lookup(int ch) {
167: ReadTableEntry entry = (ReadTableEntry) lookup(ch, null);
168: if (entry == null && ch >= 0 && ch < 0x10000) {
169: if (Character.isDigit((char) ch))
170: entry = (ReadTableEntry) lookup('0', null);
171: else if (Character.isLowerCase((char) ch))
172: entry = (ReadTableEntry) lookup('a', null);
173: else if (Character.isLetter((char) ch))
174: entry = (ReadTableEntry) lookup('A', null);
175: else if (Character.isWhitespace((char) ch))
176: entry = (ReadTableEntry) lookup(' ', null);
177: // Current code assumes lookup(')') returns null.
178: if (entry == null && ch >= 128)
179: entry = ReadTableEntry.getConstituentInstance();
180: }
181: return entry;
182: }
183:
184: protected Object makeSymbol(String name) {
185: return name.intern();
186: }
187: }
|