9870746a427e468283d4381fc0919a31d9a30161
[sbp.git] / src / edu / berkeley / sbp / ParseFailed.java
1 // Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp;
4 import edu.berkeley.sbp.*;
5 import edu.berkeley.sbp.Sequence.Position;
6 import edu.berkeley.sbp.GSS.Phase;
7 import edu.berkeley.sbp.Node;
8 import edu.berkeley.sbp.util.*;
9 import java.io.*;
10 import java.util.*;
11
12 /** thrown when the parser arrives at a state from which it is clear that no valid parse can result */
13 public class ParseFailed extends Exception {
14
15     private final Input.Location location;
16     private final Input.Region region;
17     private final Input input;
18     private final String message;
19     private final GSS gss;
20     ParseFailed() { this("", null, null, null); }
21     ParseFailed(String message, Input.Region region, Input input, GSS gss) {
22         this.region = region;
23         this.location = region.getStart();
24         this.message = message;
25         this.input = input;
26         this.gss = gss;
27     }
28     public Input.Location getLocation() { return location; }
29     private Input.Region getRegion() { return region; }
30     public String toString() {
31         StringBuilder ret = new StringBuilder();
32         ret.append(message);
33         ret.append('\n');
34         return ret.toString();
35     }
36
37     private static boolean important(Position p) {
38         if (p.isLast()) return false;
39         if (p.element() == null) return false;
40         if (!(p.element() instanceof Union)) return false;
41         Union u = (Union)p.element();
42         if (u.isSynthetic()) return false;
43         if (u.getName()==null) return false;
44         if (u.getName().length() == 0) return false;
45         char c = u.getName().charAt(0);
46         return (c >= 'A' && c <= 'Z');
47     }
48
49     static <Tok> void barf(HashMap<Element,Input.Location> sb, Node n, int indent, boolean skip, int count, Input.Location loc) {
50         if (count <= 0) {
51             barf(sb, n, indent, skip, loc);
52         } else {
53             /*
54               FIXME: removed
55             for(Node nn : (Iterable<Node>)n.parents())
56                 barf(sb, nn, indent, skip, count-1, n.phase().getLocation());
57             */
58         }
59     }
60     static <Tok> void barf(HashMap<Element,Input.Location> sb, Node n, int indent, boolean skip, Input.Location loc) {
61         if (touched.contains(n)) return;
62         touched.add(n);
63         String s = "";
64         for(int i=0; i< indent; i++) s += " ";
65         Node parent = n;
66         boolean done = false;
67         boolean alldone = false;
68         boolean go = false;
69         boolean force = false;
70         for(Position p : (Iterable<Position>)parent.state()) {
71             if (skip) p = p.next();
72             int raise = 0;
73             done = false;
74             while(p != null) {
75                 if (p.isLast()) break;
76                 if (important(p)) {
77                     Input.Location l = sb.get(p.element());
78                     if (l == null || l.compareTo(loc) < 0)
79                         sb.put(p.element(), loc);
80                     done = true;
81                     alldone = true;
82                 }
83                 /*
84                else if (p.pos-raise > 0)
85                     barf(sb, n, indent, false, 1);
86                 */
87                 if (!new Walk.Cache().possiblyEpsilon(p.element()))
88                     break;
89                 p = p.next();
90                 raise++;
91                 if (p.isLast()) {
92                     if (!done) barf(sb, n, indent, true, 1, loc);
93                     break;
94                 }
95             }
96         }
97         if (!alldone) barf(sb, n, indent, false, 1, loc);
98     }
99
100
101
102     // FIXME
103     private static HashSet<Node> touched = new HashSet<Node>();
104     static <Tok> void complain(Node n, HashMap<String,HashSet<String>> errors, boolean force, int indent) {
105         if (touched.contains(n)) return;
106         touched.add(n);
107         for(Position p : (Iterable<Position>)n.state()) {
108             //if (!p.isLast() && !p.next().isLast()) continue;
109             if (((p.isFirst() || p.isLast()) && !force)/* || p.owner().name==null*/ ||
110                 !important(p)) {
111             /*
112               FIXME: removed
113                 for(Node n2 : n.parents())
114                     complain(n2, errors, force
115                     //| p.isFirst()
116                 , indent);
117             */
118             } else {
119                 String seqname = p.owner()/*.name*/+"";
120                 HashSet<String> hs = errors.get(seqname);
121                 if (hs==null) errors.put(seqname, hs = new HashSet<String>());
122                 String s = "";
123                 hs.add(" "+p.element()+"");
124             }
125         }
126     }
127
128     static String el(Object e) {
129         String s = e.toString();
130         if (s.length()==0 || s.charAt(0)!='\"' || s.charAt(s.length()-1)!='\"') return ANSI.yellow(s);
131         s = s.substring(1);
132         s = s.substring(0, s.length()-1);
133         StringBuffer ret = new StringBuffer();
134         for(int i=0; i<s.length(); i++) {
135             if (s.charAt(i)=='\\' && i<s.length()-1) ret.append(s.charAt(++i));
136             else ret.append(s);
137         }
138         return ANSI.purple(ret.toString());
139     }
140
141     static void error(String message, GSS.Phase phase) throws ParseFailed {
142         error(message, phase.getLocation(), phase.getToken(),
143               phase, phase.getRegion(), phase.getGSS().getInput(), phase.getGSS());
144     }
145     static void error(String message,
146                       Input.Location loc,
147                       Object token,
148                       Iterable<Node> nodes,
149                       Input.Region region,
150                       Input input,
151                       GSS gss) throws ParseFailed{
152         String lookAhead = token==null ? "<EOF>" : token.toString();
153         StringBuffer ret = new StringBuffer();
154         ret.append(ANSI.bold(ANSI.red(message)));
155         if (token != null) {
156             ret.append(" \'");
157             ret.append(ANSI.cyan(StringUtil.escapify(token+"", "\\\'\r\n")));
158             ret.append("\'");
159         }
160         ret.append(" at ");
161         ret.append(ANSI.yellow(region+""));
162         if (input != null) {
163             ret.append('\n');
164             ret.append("     text: ");
165             int budget = 60;
166             String second = input.showRegion(region);
167             budget -= second.length();
168             Input.Location after = region.getEnd();
169             for(int i=0; i<10; i++) after = after.next() == null ? after : after.next();
170             String third = input.showRegion(region.getEnd().createRegion(after));
171             budget -= third.length();
172             Input.Location before = region.getStart();
173             for(int i=0; i<budget; i++) before = before.prev() == null ? before : before.prev();
174             String first = input.showRegion(before.createRegion(region.getStart()));
175             ret.append(ANSI.cyan(first));
176             ret.append(ANSI.invert(ANSI.red(second)));
177             ret.append(ANSI.cyan(third));
178             /*
179             ret.append('\n');
180             ret.append("           ");
181             for(int i=0; i<first.length(); i++) ret.append(' ');
182             for(int i=0; i<second.length(); i++) ret.append(ANSI.red("^"));
183             */
184         }
185         HashMap<Element,Input.Location> hm = new HashMap<Element,Input.Location>();
186         for(Node no : nodes)
187             barf(hm, no, 0, false, region.getStart());
188         ret.append("\n expected: ");
189         Set<Element> hs = hm.keySet();
190         if (hs.size() == 1) {
191             ret.append(hs.iterator().next());
192         } else {
193             int i=0;
194             for(Element s : hs) {
195                 Input.Location loc2 = hm.get(s);
196                 if (i==0) {
197                     ret.append("" + ANSI.purple(s));
198                 } else {
199                     ret.append("\n        or " + ANSI.purple(s));
200                 }
201                 Input.Region reg = loc2.createRegion(region.getEnd());
202                 ret.append(" to match \"" + ANSI.cyan(input.showRegion(reg)) + "\" at " + ANSI.yellow(reg));
203                 i++;
204             }
205         }
206         /*
207         ret.append("\n  The author of SBP apologizes for the these nearly-useless error messages:\n\n");
208         HashMap<String,HashSet<String>> errors = new HashMap<String,HashSet<String>>();
209         for(Node n : nodes) {
210             //System.out.println(n.state);
211             complain(n, errors, false, 0);
212         }
213         for(String s : errors.keySet()) {
214             ret.append("    while parsing " + ANSI.yellow(s));
215             HashSet<String> hs = errors.get(s);
216
217             if (hs.size()==1) ret.append("\n      expected " + ANSI.yellow(el(hs.iterator().next())) + "\n\n");
218             else {
219                 ret.append("\n      expected ");
220                 boolean first = true;
221                 for(String s2 : hs) {
222                     if (!first) ret.append(" or ");
223                     first = false;
224                     ret.append(ANSI.yellow(el(s2)));
225                 }
226                 ret.append("\n\n");
227             }
228         }
229         */
230         throw new ParseFailed(ret.toString(), region, input, gss);
231     }
232
233 }