checkpoint
[sbp.git] / src / edu / berkeley / sbp / misc / CharToken.java
1 package edu.berkeley.sbp.misc;
2 import java.io.*;
3 import java.util.*;
4 import java.lang.reflect.*;
5 import java.lang.ref.*;
6 import edu.berkeley.sbp.*;
7 import edu.berkeley.sbp.Token.Location;
8 import edu.berkeley.sbp.util.*;
9
10 /** an implementation of Token for streams of Java <tt>char</tt> values */
11 public class CharToken implements IntegerMappable {
12
13     // Public //////////////////////////////////////////////////////////////////////////////
14
15     public static class CharToStringParser extends Parser<CharToken,String> {
16         public CharToStringParser(Union u) { super(u, new IntegerTopology<CharToken>()); }
17         public Forest<String> shiftToken(CharToken ct, Location loc) {
18             return Forest.create(loc, ct.result(), null, false, false);
19         }
20     }
21
22     public static class CharRange extends Atom<CharToken> {
23         private String esc(char c) { return StringUtil.escapify(c+"", "[]-~\\\"\'"); }
24         private Topology<CharToken> t;
25         public CharRange(Topology<CharToken> t) { this.t = t; }
26         public Topology<CharToken> top() { return t; }
27         public String toString() {
28             StringBuffer sb = new StringBuffer();
29             sb.append('[');
30             Range.Set ranges = ((IntegerTopology)top()).getRanges();
31             if (ranges.size() == -1 || ranges.size() > Character.MAX_VALUE/2) {
32                 sb.append('~');
33                 ranges = ranges.complement();
34             }
35             ranges = ranges.intersect(all);
36             for(Range r : ranges) {
37                 if (r.isMinNegInf() || r.isMaxPosInf()) throw new Error("should not happen");
38                 if (r.getMin()==r.getMax()) {
39                     sb.append(esc((char)r.getMin()));
40                 } else{
41                     sb.append(esc((char)r.getMin()));
42                     sb.append('-');
43                     sb.append(esc((char)r.getMax()));
44                 }
45             }
46             sb.append(']');
47             return sb.toString();
48         }
49     }
50
51     /** returns an element matching all characters between <tt>start</tt> and <tt>end</tt>, inclusive */
52     public static Atom positiveRange(char start, char end) {
53         return new CharRange(new IntegerTopology<CharToken>(new Range.Set(new Range((int)start, (int)end))));
54     }
55
56     /** returns an element matching all characters <b>not</b> between <tt>start</tt> and <tt>end</tt>, inclusive */
57     public static Atom negativeRange(char start, char end) {
58         return new CharRange(new IntegerTopology<CharToken>(new Range.Set(new Range((int)start, (int)end)).complement().intersect(all)));
59     }
60
61     public static final Atom leftBrace  = new CharRange(new IntegerTopology<CharToken>(9998)) { public String toString() { return "{"; } };
62     public static final Atom rightBrace = new CharRange(new IntegerTopology<CharToken>(9999)) { public String toString() { return "}"; } };
63     public static final CharToken left       = new CharToken((char)9998);
64     public static final CharToken right      = new CharToken((char)9999);
65
66     private static final Range.Set all = new Range.Set(new Range(0, Character.MAX_VALUE));
67     public  static final Atom      any = new CharRange(new IntegerTopology<CharToken>(all));
68     public  static final Atom     none = new CharRange(new IntegerTopology<CharToken>());
69     public static IntegerTopology<CharToken> range(Range r) { return new IntegerTopology<CharToken>(r); }
70     public static Atom set(Range.Set r) { return new CharRange(new IntegerTopology<CharToken>(r)); }
71
72     /** returns an element which exactly matches the string given */
73     public static Element string(String s) {
74         if (s.length() == 0) return Union.epsilon;
75         final String escapified = "\""+StringUtil.escapify(s, "\"\r\n\\")+"\"";
76         Element ret;
77         if (s.length() == 1) {
78             ret =
79                 new CharRange(new IntegerTopology<CharToken>((int)s.charAt(0))) {
80                     public String toString() { return escapified; } };
81         } else {
82             Union ret2 = new Union("\""+s+"\"_str", true) {
83                     public String toString() { return escapified; } };
84             Element[] refs = new Element[s.length()];
85             for(int i=0; i<refs.length; i++) refs[i] = new CharRange(new IntegerTopology<CharToken>((int)s.charAt(i)));
86             ret2.add(Sequence.constant(refs, s, null, null));
87             ret = ret2;
88         }
89         return ret;
90     }
91
92     /** FIXME */
93     public static Topology<CharToken> top() { return new IntegerTopology<CharToken>(); }
94     public static Topology<CharToken> top(String s) throws java.text.ParseException {
95         return new IntegerTopology<CharToken>(Range.Set.parse(s));
96     }
97
98     // Private //////////////////////////////////////////////////////////////////////////////
99
100     public final char c;
101     public CharToken(char c)        { this.c = c; }
102     public String result()          { return c+""; }
103     public String  toString()       { return "\'"+StringUtil.escapify(c+"")+"\'"; }
104
105     //////////////////////////////////////////////////////////////////////////////////////////
106
107     public int toInt() { return (int)c; }
108
109     // Statics //////////////////////////////////////////////////////////////////////////////
110
111     public static class CartesianLocation implements Location {
112         public final int line;
113         public final int col;
114         public String toString()            { return line + ":" + col; }
115         public CartesianLocation(int line, int col) { this.line = line; this.col = col; }
116     }
117     
118     /** an implementation of Token.Stream for sequences of characters */
119     public static class Stream implements Token.Stream<CharToken> {
120         private final String message;
121         private final Reader r;
122         private int line  = 1;
123         private int col   = 1;
124
125         public Stream(String s)                { this(new StringReader(s)); }
126
127         public Stream(Reader r)                { this(r, null); }
128         public Stream(Reader r,      String s) { this.r = r; this.message = s; }
129
130         public Stream(InputStream i)           { this(i, null); }
131         public Stream(InputStream i, String s) { this(new InputStreamReader(i), s); }
132
133         private Line currentLine = new Line();
134         private class Line {
135             public StringBuffer line = new StringBuffer();
136         }
137
138         private class LocWrap implements Location {
139             Line myline = Stream.this.currentLine;
140             public final int line;
141             public final int col;
142             public String toString()            { return line + ":" + col; }
143             public LocWrap(int line, int col) { this.line = line; this.col = col; }
144             public String getContext() {
145                 StringBuffer spaces = new StringBuffer();
146                 for(int i=0; i<col-1; i++) spaces.append(' ');
147                 spaces.append('^');
148                 return "  " + myline.line.toString() + "\n  " + spaces.toString();
149             }
150         }
151
152         long then = 0;
153         private Location location = new LocWrap(1, 1);
154         public Location getLocation() { return location; }
155         public CharToken next(int numstates, int resets, int waits) throws IOException {
156             int i = r.read();
157             if (i==-1) return null;
158             char c = (char)i;
159             location = new LocWrap(line, col);
160             CharToken ret = new CharToken(c);
161             String s = line + "";
162             while(s.length() < 4) s = " " + s;
163             s = "line "+s+", col " + col;
164             while(s.length() < 20) s += " ";
165             s += "[ambiguity level: " + (numstates-1) + "] [resets: " + resets + "] [waits: " + waits + "]";
166             long now = System.currentTimeMillis();
167             if (now-then > 10) {
168                 then = now;
169                 System.out.print("  "+(message==null?"":message)+" " + s + "                                \r");
170             }
171             if (c=='\n') { 
172                 currentLine = new Line();
173                 line++;
174                 col = 1;
175             } else {
176                 currentLine.line.append(c);
177                 col++;
178             }
179             return ret;
180         }
181     }
182
183 }