1 // Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
3 package edu.berkeley.sbp;
4 import edu.berkeley.sbp.*;
5 import edu.berkeley.sbp.Sequence.Pos;
6 import edu.berkeley.sbp.Sequence.Pos;
7 import edu.berkeley.sbp.GSS.Phase;
8 import edu.berkeley.sbp.StateNode;
9 import edu.berkeley.sbp.util.*;
13 /** thrown when the parser arrives at a state from which it is clear that no valid parse can result */
14 public class ParseFailed extends Exception {
16 private final Input.Location location;
17 private final Input.Region region;
18 private final Input input;
19 private final String message;
20 private final GSS gss;
21 ParseFailed() { this("", null, null, null); }
22 ParseFailed(String message, Input.Region region, Input input, GSS gss) {
24 this.location = region.getStart();
25 this.message = message;
29 public Input.Location getLocation() { return location; }
30 private Input.Region getRegion() { return region; }
31 public String toString() {
32 StringBuilder ret = new StringBuilder();
35 return ret.toString();
38 private static boolean important(Pos p) {
39 if (p.isLast()) return false;
40 if (p.element() == null) return false;
41 if (!(p.element() instanceof Union)) return false;
42 Union u = (Union)p.element();
43 if (u.isSynthetic()) return false;
44 if (u.getName()==null) return false;
45 if (u.getName().length() == 0) return false;
46 char c = u.getName().charAt(0);
47 return (c >= 'A' && c <= 'Z');
50 static <Tok> void barf(HashMap<Element,Input.Location> sb, StateNode n, int indent, boolean skip, int count, Input.Location loc) {
52 barf(sb, n, indent, skip, loc);
56 for(StateNode nn : (Iterable<StateNode>)n.parents())
57 barf(sb, nn, indent, skip, count-1, n.phase().getLocation());
61 static <Tok> void barf(HashMap<Element,Input.Location> sb, StateNode n, int indent, boolean skip, Input.Location loc) {
62 if (touched.contains(n)) return;
65 for(int i=0; i< indent; i++) s += " ";
68 boolean alldone = false;
70 boolean force = false;
71 for(Pos pp : (Iterable<Pos>)parent.state().positions()) {
73 if (skip) p = p.next();
77 if (p.isLast()) break;
79 Input.Location l = sb.get(p.element());
80 if (l == null || l.compareTo(loc) < 0)
81 sb.put(p.element(), loc);
86 else if (p.pos-raise > 0)
87 barf(sb, n, indent, false, 1);
88 if (!new Grammar(null, null).possiblyEpsilon(p.element()))
94 if (!done) barf(sb, n, indent, true, 1, loc);
99 if (!alldone) barf(sb, n, indent, false, 1, loc);
105 private static HashSet<StateNode> touched = new HashSet<StateNode>();
106 static <Tok> void complain(StateNode n, HashMap<String,HashSet<String>> errors, boolean force, int indent) {
107 if (touched.contains(n)) return;
109 for(Pos p : (Iterable<Pos>)n.state()) {
110 //if (!p.isLast() && !p.next().isLast()) continue;
111 if (((p.isFirst() || p.isLast()) && !force)/* || p.owner().name==null*/ ||
115 for(StateNode n2 : n.parents())
116 complain(n2, errors, force
121 String seqname = p.owner()/*.name*/+"";
122 HashSet<String> hs = errors.get(seqname);
123 if (hs==null) errors.put(seqname, hs = new HashSet<String>());
125 hs.add(" "+p.element()+"");
130 static String el(Object e) {
131 String s = e.toString();
132 if (s.length()==0 || s.charAt(0)!='\"' || s.charAt(s.length()-1)!='\"') return ANSI.yellow(s);
134 s = s.substring(0, s.length()-1);
135 StringBuffer ret = new StringBuffer();
136 for(int i=0; i<s.length(); i++) {
137 if (s.charAt(i)=='\\' && i<s.length()-1) ret.append(s.charAt(++i));
140 return ANSI.purple(ret.toString());
143 static void error(String message, GSS.Phase phase, Object token, Input.Region region) throws ParseFailed {
148 phase.getGSS().getInput(),
151 private static void error(String message,
153 Iterable<StateNode> nodes,
156 GSS gss) throws ParseFailed{
157 String lookAhead = token==null ? "<EOF>" : token.toString();
158 StringBuffer ret = new StringBuffer();
159 ret.append(ANSI.bold(ANSI.red(message)));
160 String toks = token+"";
162 ret.append(ANSI.yellow(region+""));
165 ret.append(" text: ");
167 String second = input.showRegion(region, 60);
168 budget -= second.length();
169 Input.Location after = region.getEnd();
170 for(int i=0; i<10; i++) after = after.next() == null ? after : after.next();
171 String third = input.showRegion(region.getEnd().createRegion(after), 60);
172 budget -= third.length();
173 Input.Location before = region.getStart();
174 for(int i=0; i<budget; i++) before = before.prev() == null ? before : before.prev();
175 String first = input.showRegion(before.createRegion(region.getStart()), 60);
176 ret.append(ANSI.cyan(first));
177 ret.append(ANSI.invert(ANSI.red(second)));
178 ret.append(ANSI.cyan(third));
182 for(int i=0; i<first.length(); i++) ret.append(' ');
183 for(int i=0; i<second.length(); i++) ret.append(ANSI.red("^"));
186 HashMap<Element,Input.Location> hm = new HashMap<Element,Input.Location>();
187 for(StateNode no : nodes)
188 barf(hm, no, 0, false, region.getStart());
189 ret.append("\n expected: ");
190 Set<Element> hs = hm.keySet();
191 if (hs.size() == 1) {
192 ret.append(hs.iterator().next());
195 for(Element s : hs) {
196 Input.Location loc2 = hm.get(s);
198 ret.append("" + ANSI.purple(s));
200 ret.append("\n or " + ANSI.purple(s));
202 Input.Region reg = loc2.createRegion(region.getEnd());
203 ret.append(" to match \"" + ANSI.cyan(input.showRegion(reg, 60)) + "\" at " + ANSI.yellow(reg));
208 ret.append("\n The author of SBP apologizes for the these nearly-useless error messages:\n\n");
209 HashMap<String,HashSet<String>> errors = new HashMap<String,HashSet<String>>();
210 for(StateNode n : nodes) {
211 //System.out.println(n.state);
212 complain(n, errors, false, 0);
214 for(String s : errors.keySet()) {
215 ret.append(" while parsing " + ANSI.yellow(s));
216 HashSet<String> hs = errors.get(s);
218 if (hs.size()==1) ret.append("\n expected " + ANSI.yellow(el(hs.iterator().next())) + "\n\n");
220 ret.append("\n expected ");
221 boolean first = true;
222 for(String s2 : hs) {
223 if (!first) ret.append(" or ");
225 ret.append(ANSI.yellow(el(s2)));
231 throw new ParseFailed(ret.toString(), region, input, gss);