001: package gnu.q2.lang;
002:
003: import gnu.kawa.lispexpr.*;
004: import gnu.expr.QuoteExp;
005: import gnu.text.*;
006: import gnu.mapping.*;
007: import gnu.lists.*;
008: import gnu.expr.Keyword;
009: import gnu.kawa.xml.MakeAttribute;
010:
011: /** A class to read Scheme forms (S-expressions). */
012:
013: public class Q2Read extends LispReader {
014: void init() {
015: initialColonIsKeyword = false;
016: ((InPort) port).readState = ' ';
017: }
018:
019: public Q2Read(InPort port) {
020: super (port);
021: init();
022: }
023:
024: public Q2Read(InPort port, SourceMessages messages) {
025: super (port, messages);
026: init();
027: }
028:
029: int skipIndentation() throws java.io.IOException, SyntaxException {
030: int numTabs = 0, numSpaces = 0;
031: int ch = port.read();
032: while (ch == '\t') {
033: numTabs++;
034: ch = port.read();
035: }
036: while (ch == ' ') {
037: numSpaces++;
038: ch = port.read();
039: }
040: if (ch < 0)
041: return -1;
042: port.unread();
043: return (numTabs << 16) + numSpaces;
044: }
045:
046: boolean singleLine() {
047: return interactive && nesting == 0;
048: }
049:
050: public Object readCommand() throws java.io.IOException,
051: SyntaxException {
052: return readCommand(false);
053: }
054:
055: public Object readCommand(boolean forceList)
056: throws java.io.IOException, SyntaxException {
057: int line = port.getLineNumber();
058: int startColumn = port.getColumnNumber();
059: int lastColumn = startColumn;
060: Object obj = LList.Empty;
061: PairWithPosition pair = null, last = null;
062: for (;;) {
063: int ch = read();
064: if (ch < 0)
065: break;
066: if (ch == ' ' || ch == '\t')
067: continue;
068: unread();
069: if (ch == ')')
070: break;
071: line = port.getLineNumber();
072: int column = port.getColumnNumber();
073: while (ch == '\r' || ch == '\n') {
074: if (singleLine())
075: return obj;
076: ch = read();
077: skipIndentation(); // skipHorSpace.
078: column = port.getColumnNumber();
079: ch = peek();
080: if (column <= startColumn)
081: break;
082: }
083: if (column <= startColumn && last != null)
084: break;
085: Object next;
086: if (column == lastColumn && last != null)
087: next = readCommand();
088: else if (column < lastColumn && last != null) {
089: PairWithPosition p = pair;
090: for (;;) {
091: Object n = p.cdr;
092: if (n == LList.Empty)
093: break;
094: PairWithPosition np = (PairWithPosition) n;
095: int pColumn = np.getColumnNumber() - 1;
096: if (pColumn >= column) {
097: if (pColumn > column)
098: error('e',
099: "some tokens on previous line indented more than current line");
100: n = np.cdr;
101: if (n != LList.Empty) {
102: if (((PairWithPosition) n)
103: .getColumnNumber() - 1 == column) {
104: p = (PairWithPosition) n;
105: continue;
106: }
107: last = (PairWithPosition) makePair(np, port
108: .getLineNumber(), column);
109: p.cdr = last;
110: }
111: break;
112: }
113: p = np;
114: }
115: next = readCommand();
116: } else
117: next = readObject();
118: if (next == Sequence.eofValue)
119: break;
120: lastColumn = column;
121: String filename = port.getName();
122: PairWithPosition cur = PairWithPosition.make(next,
123: LList.Empty, filename, line + 1, column + 1);
124: if (last == null) {
125: pair = cur;
126: obj = cur;
127: } else if (last.car instanceof Keyword) {
128: Object name = new QuoteExp(((Keyword) last.car)
129: .getName());
130: last.car = new PairWithPosition(last,
131: MakeAttribute.makeAttribute,
132: new PairWithPosition(last, name, cur));
133: continue;
134: } else
135: last.cdr = cur;
136: last = cur;
137: }
138: if (!forceList) {
139: if (obj == last)
140: obj = last.car;
141: else if (last == null)
142: obj = QuoteExp.voidExp;
143: }
144: return obj;
145: }
146:
147: public static Object readObject(InPort port)
148: throws java.io.IOException, SyntaxException {
149: return (new Q2Read(port)).readObject();
150: }
151:
152: /** Record '[' location for error messages. */
153: String expressionStartFile;
154: int expressionStartLine;
155: int expressionStartColumn;
156:
157: void saveExpressionStartPosition() {
158: expressionStartFile = port.getName();
159: expressionStartLine = port.getLineNumber();
160: expressionStartColumn = port.getColumnNumber();
161: }
162: }
163:
164: class Q2ReaderParens extends ReaderDispatchMisc {
165: public Object read(Lexer in, int ch, int count)
166: throws java.io.IOException, SyntaxException {
167: Q2Read reader = (Q2Read) in;
168: char saveReadState = reader.pushNesting('(');
169: try {
170: Object result = reader.readCommand(true);
171:
172: LineBufferedReader port = reader.getPort();
173: if (port.read() != ')')
174: reader.error("missing ')'");
175: return result;
176: } finally {
177: reader.popNesting(saveReadState);
178: }
179: }
180:
181: }
|