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.Values;
008:
009: public class ReaderParens extends ReadTableEntry {
010: char open;
011: char close;
012: int kind;
013:
014: public int getKind() {
015: return kind;
016: }
017:
018: private static ReaderParens instance;
019:
020: public static ReaderParens getInstance(char open, char close) {
021: return getInstance(open, close, ReadTable.TERMINATING_MACRO);
022: }
023:
024: public static ReaderParens getInstance(char open, char close,
025: int kind) {
026: if (open == '(' && close == ')'
027: && kind == ReadTable.TERMINATING_MACRO) {
028: if (instance == null)
029: instance = new ReaderParens(open, close, kind);
030: return instance;
031: } else {
032: return new ReaderParens(open, close, kind);
033: }
034: }
035:
036: public ReaderParens(char open, char close, int kind) {
037: this .open = open;
038: this .close = close;
039: this .kind = kind;
040: }
041:
042: /** Read a list (possibly improper) of zero or more Scheme forms.
043: * Assumes '(' has been read.
044: */
045: public Object read(Lexer in, int ch, int count)
046: throws java.io.IOException, SyntaxException {
047: return readList((LispReader) in, ch, count, close);
048: }
049:
050: public static Object readList(LispReader lexer, int ch, int count,
051: int close) throws java.io.IOException, SyntaxException {
052: LineBufferedReader port = lexer.getPort();
053: char saveReadState = lexer
054: .pushNesting(close == ']' ? '[' : '(');
055: int startLine = port.getLineNumber();
056: int startColumn = port.getColumnNumber();
057: try {
058: Object last = null;
059: Object list = lexer.makeNil();
060: boolean sawDot = false;
061: boolean sawDotCdr = false;
062: ReadTable readTable = ReadTable.getCurrent();
063: for (;;) {
064: int line = port.getLineNumber();
065: int column = port.getColumnNumber();
066: ch = port.read();
067: if (ch == close)
068: break;
069: if (ch < 0)
070: lexer.eofError(
071: "unexpected EOF in list starting here",
072: startLine + 1, startColumn);
073: ReadTableEntry entry;
074: if (ch == '.') {
075: ch = port.peek();
076: entry = readTable.lookup(ch);
077: int kind = entry == null ? ReadTable.ILLEGAL
078: : entry.getKind();
079: if (kind == ReadTable.WHITESPACE
080: || kind == ReadTable.TERMINATING_MACRO
081: || kind == ReadTable.ILLEGAL) {
082: port.skip();
083: column++;
084: if (ch == close) {
085: lexer.error("unexpected '" + ((char) close)
086: + "' after '.'");
087: break;
088: }
089: if (ch < 0)
090: lexer
091: .eofError(
092: "unexpected EOF in list starting here",
093: startLine + 1, startColumn);
094: if (sawDot) {
095: lexer.error("multiple '.' in list");
096: sawDotCdr = false;
097: list = lexer.makeNil();
098: last = null;
099: }
100: sawDot = true;
101: } else {
102: // Treat '.' as start of token.
103: ch = '.';
104: entry = ReadTableEntry.getConstituentInstance();
105: }
106: } else
107: entry = readTable.lookup(ch);
108: Object value = lexer.readValues(ch, entry, readTable);
109: if (value == Values.empty)
110: continue;
111: value = lexer.handlePostfix(value, readTable, line,
112: column);
113:
114: // ( a1 ... an . cdr) creates an n-element list ended by
115: // cdr. If n==0, a reasonable (and common) extension is to
116: // interpret this as a 0-element list ended by cdr - i.e.
117: // just cdr by itself.
118:
119: if (sawDotCdr) {
120: lexer.error("multiple values after '.'");
121: last = null;
122: list = lexer.makeNil();
123: sawDotCdr = false;
124: continue;
125: } else if (sawDot) {
126: sawDotCdr = true;
127: } else {
128: if (last == null) {
129: line = startLine;
130: column = startColumn - 1;
131: }
132: value = lexer.makePair(value, line, column);
133: }
134: if (last == null)
135: list = value;
136: else
137: lexer.setCdr(last, value);
138: last = value;
139: }
140: return list;
141: } finally {
142: lexer.popNesting(saveReadState);
143: }
144:
145: }
146: }
|