10150d57b66e58aef1c4c18823736dfdce8ad6b9
[sbp.git] / src / edu / berkeley / sbp / chr / CharInput.java
1 // Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp.chr;
4 import java.io.*;
5 import java.util.*;
6 import java.lang.reflect.*;
7 import java.lang.ref.*;
8 import edu.berkeley.sbp.*;
9 import edu.berkeley.sbp.util.*;
10 import edu.berkeley.sbp.misc.*;
11 import edu.berkeley.sbp.Input.Location;
12
13 public class CharInput extends Cartesian.Input<Character> {
14
15     private static class RollbackReader extends Reader {
16         private final Reader r;
17         public RollbackReader(Reader r) { this.r = r; }
18         
19         private char[] queue = new char[1024];
20         private int head = 0;
21         private int tail = 0;
22
23         private void unread(char c) {
24             if (tail >= queue.length) {
25                 if (tail - head > queue.length/2) {
26                     char[] queue2 = new char[queue.length * 2];
27                     System.arraycopy(queue, head, queue2, 0, tail-head);
28                 } else {
29                     System.arraycopy(queue, head, queue, 0, tail-head);
30                 }
31                 tail = tail-head;
32                 head = 0;
33             }
34             queue[tail++] = c;
35         }
36
37         public void close() throws IOException { r.close(); }
38         public int read() throws IOException {
39             if (tail>head)
40                 return queue[head++];
41             return r.read();
42         }
43         public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); }
44         public int read(char cbuf[], int off, int len) throws IOException {
45             if (tail>head) {
46                 int count = Math.min(len, tail-head);
47                 System.arraycopy(queue, head, cbuf, off, count);
48                 head += count;
49                 return count;
50             }
51             return r.read(cbuf, off, len);
52         }
53         public long skip(long n) throws IOException { return r.skip(n); }
54         public boolean ready() throws IOException { return true; }
55         public boolean markSupported() { return false; }
56         public void mark(int readAheadLimit) throws IOException { throw new IOException("not supported"); }
57         public void reset() throws IOException { throw new IOException("not supported"); }
58     }
59
60     private final RollbackReader r;
61     
62     public CharInput(String s)                { this(new StringReader(s)); }
63     public CharInput(Reader r)                { this(r, null); }
64     public CharInput(Reader r,      String s) { this.r = new RollbackReader(new BufferedReader(r)); }
65     public CharInput(InputStream i)           { this(i, null); }
66     public CharInput(InputStream i, String s) { this(new InputStreamReader(i), s); }
67
68     public CharInput(InputStream i, String s, boolean indent) {
69         this(new InputStreamReader(i), s);
70         this.indent = indent;
71     }
72
73     boolean cr = false;
74     boolean indent = false;
75     private int count = 0;
76     private StringBuilder cache = new StringBuilder();
77     
78     public void setCacheEnabled(boolean enabled) {
79         if (!enabled) cache = null;
80         else if (cache == null) cache = new StringBuilder();
81     }
82
83     int indentation = -1;
84     int lastIndentation = 0;
85     int queuedIndentation = 0;
86     char queuedCharacter = ' ';
87     int delta = 0;
88
89     public boolean   isCR() { return cr; }
90     public Character _next() throws IOException {
91         Character ret = __next();
92         if (ret==null) return null;
93         char c = ret.charValue();
94         if (indent) {
95             if (ret==CharAtom.left)  System.out.print("\033[31m{\033[0m");
96             else if (ret==CharAtom.right) System.out.print("\033[31m}\033[0m");
97             else System.out.print(c+"");
98         }
99         return ret;
100     }
101     public Character __next() throws IOException {
102
103         cr = false;
104
105         if (queuedIndentation < 0) {
106             queuedIndentation++;
107             return CharAtom.right;
108         }
109         if (queuedSpaces > 0) {
110             queuedSpaces--;
111             return ' ';
112         }
113         if (queuedIndentation > 0) {
114             queuedIndentation--;
115             return CharAtom.left;
116         }
117
118         if (queuedCharacter != ' ') {
119             char ret = queuedCharacter;
120             queuedCharacter = ' ';
121             return ret;
122         }
123
124         int i = r.read();
125         if (i==-1) {
126             /*System.err.print("\r...done       \r"); */
127             if (indent && indentation >= 0) {
128                 redent(indentation - lastIndentation);
129                 //System.err.println("\r                   \rindent: " + (indentation - lastIndentation));
130                 lastIndentation = indentation;
131                 indentation = -1;
132                 return __next();
133             }
134             return null;
135         }
136         char c = (char)i;
137         if (cache != null) cache.append(c);
138         cr = c=='\n';
139
140         if (indent)
141             if (cr) {
142                 indentation = 0;
143             } else if (c==' ' && indentation >= 0) {
144                 indentation++;
145             } else if (indentation >= 0) {
146                 //System.err.println("\r                   \rindent: " + (indentation - lastIndentation));
147                 redent(indentation - lastIndentation);
148                 r.unread(c);
149                 lastIndentation = indentation;
150                 indentation = -1;
151                 return __next();
152             }
153
154         return c;
155     }
156
157     private void redent(int i) {
158         if (i<0) { r.unread(CharAtom.right); redent(i+1); return; }
159         if (i>0) { r.unread(CharAtom.left); redent(i-1); return; }
160     }
161
162     int queuedSpaces = 0;
163
164     public String showRegion(Region<Character> rc) {
165         if (cache == null) return null;
166         Cartesian.Region r = (Cartesian.Region)rc;
167         int start = r.getStart().getScalar()+1;
168         int end = r.getEnd().getScalar()+1;
169         if (start < 0) start = 0;
170         if (end < start) end = start;
171         if (end > cache.length()) end = cache.length();
172         String ret;
173         if (end-start < 60) ret = cachesubstring(start, end);
174         else ret = cachesubstring(start, start+25) +
175                  "..." +
176                  cachesubstring(end-25, end);
177         return StringUtil.escapify(ret, "\n\r");
178     }
179
180     private String cachesubstring(int start, int end) {
181         if (start < 0) start = 0;
182         if (end < 0)   end = 0;
183         if (start >= cache.length()) start = cache.length();
184         if (end >= cache.length()) end = cache.length();
185         return cache.substring(start, end);
186     }
187
188 }