use Sequence.Pos rather than Sequence.Position wherever possible
[sbp.git] / src / edu / berkeley / sbp / ParseFailed.java
1 // Copyright 2006-2007 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.Pos;
6 import edu.berkeley.sbp.Sequence.Pos;
7 import edu.berkeley.sbp.GSS.Phase;
8 import edu.berkeley.sbp.Node;
9 import edu.berkeley.sbp.util.*;
10 import java.io.*;
11 import java.util.*;
12
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 {
15
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) {
23         this.region = region;
24         this.location = region.getStart();
25         this.message = message;
26         this.input = input;
27         this.gss = gss;
28     }
29     public Input.Location getLocation() { return location; }
30     private Input.Region getRegion() { return region; }
31     public String toString() {
32         StringBuilder ret = new StringBuilder();
33         ret.append(message);
34         ret.append('\n');
35         return ret.toString();
36     }
37
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');
48     }
49
50     static <Tok> void barf(HashMap<Element,Input.Location> sb, Node n, int indent, boolean skip, int count, Input.Location loc) {
51         if (count <= 0) {
52             barf(sb, n, indent, skip, loc);
53         } else {
54             /*
55               FIXME: removed
56             for(Node nn : (Iterable<Node>)n.parents())
57                 barf(sb, nn, indent, skip, count-1, n.phase().getLocation());
58             */
59         }
60     }
61     static <Tok> void barf(HashMap<Element,Input.Location> sb, Node n, int indent, boolean skip, Input.Location loc) {
62         if (touched.contains(n)) return;
63         touched.add(n);
64         String s = "";
65         for(int i=0; i< indent; i++) s += " ";
66         Node parent = n;
67         boolean done = false;
68         boolean alldone = false;
69         boolean go = false;
70         boolean force = false;
71         for(Pos pp : (Iterable<Pos>)parent.state().positions()) {
72             Pos p = (Pos)pp;
73             if (skip) p = p.next();
74             int raise = 0;
75             done = false;
76             while(p != null) {
77                 if (p.isLast()) break;
78                 if (important(p)) {
79                     Input.Location l = sb.get(p.element());
80                     if (l == null || l.compareTo(loc) < 0)
81                         sb.put(p.element(), loc);
82                     done = true;
83                     alldone = true;
84                 }
85                 /*
86                else if (p.pos-raise > 0)
87                     barf(sb, n, indent, false, 1);
88                 if (!new Grammar(null, null).possiblyEpsilon(p.element()))
89                     break;
90                 */
91                 p = p.next();
92                 raise++;
93                 if (p.isLast()) {
94                     if (!done) barf(sb, n, indent, true, 1, loc);
95                     break;
96                 }
97             }
98         }
99         if (!alldone) barf(sb, n, indent, false, 1, loc);
100     }
101
102
103
104     // FIXME
105     private static HashSet<Node> touched = new HashSet<Node>();
106     static <Tok> void complain(Node n, HashMap<String,HashSet<String>> errors, boolean force, int indent) {
107         if (touched.contains(n)) return;
108         touched.add(n);
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*/ ||
112                 !important(p)) {
113             /*
114               FIXME: removed
115                 for(Node n2 : n.parents())
116                     complain(n2, errors, force
117                     //| p.isFirst()
118                 , indent);
119             */
120             } else {
121                 String seqname = p.owner()/*.name*/+"";
122                 HashSet<String> hs = errors.get(seqname);
123                 if (hs==null) errors.put(seqname, hs = new HashSet<String>());
124                 String s = "";
125                 hs.add(" "+p.element()+"");
126             }
127         }
128     }
129
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);
133         s = s.substring(1);
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));
138             else ret.append(s);
139         }
140         return ANSI.purple(ret.toString());
141     }
142
143     static void error(String message, GSS.Phase phase, Object token, Input.Region region) throws ParseFailed {
144         error(message,
145               token,
146               phase,
147               region,
148               phase.getGSS().getInput(),
149               phase.getGSS());
150     }
151     private static void error(String message,
152                               Object token,
153                               Iterable<Node> nodes,
154                               Input.Region region,
155                               Input input,
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+"";
161         ret.append(" at ");
162         ret.append(ANSI.yellow(region+""));
163         if (input != null) {
164             ret.append('\n');
165             ret.append("     text: ");
166             int budget = 60;
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));
179             /*
180             ret.append('\n');
181             ret.append("           ");
182             for(int i=0; i<first.length(); i++) ret.append(' ');
183             for(int i=0; i<second.length(); i++) ret.append(ANSI.red("^"));
184             */
185         }
186         HashMap<Element,Input.Location> hm = new HashMap<Element,Input.Location>();
187         for(Node 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());
193         } else {
194             int i=0;
195             for(Element s : hs) {
196                 Input.Location loc2 = hm.get(s);
197                 if (i==0) {
198                     ret.append("" + ANSI.purple(s));
199                 } else {
200                     ret.append("\n        or " + ANSI.purple(s));
201                 }
202                 Input.Region reg = loc2.createRegion(region.getEnd());
203                 ret.append(" to match \"" + ANSI.cyan(input.showRegion(reg, 60)) + "\" at " + ANSI.yellow(reg));
204                 i++;
205             }
206         }
207         /*
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(Node n : nodes) {
211             //System.out.println(n.state);
212             complain(n, errors, false, 0);
213         }
214         for(String s : errors.keySet()) {
215             ret.append("    while parsing " + ANSI.yellow(s));
216             HashSet<String> hs = errors.get(s);
217
218             if (hs.size()==1) ret.append("\n      expected " + ANSI.yellow(el(hs.iterator().next())) + "\n\n");
219             else {
220                 ret.append("\n      expected ");
221                 boolean first = true;
222                 for(String s2 : hs) {
223                     if (!first) ret.append(" or ");
224                     first = false;
225                     ret.append(ANSI.yellow(el(s2)));
226                 }
227                 ret.append("\n\n");
228             }
229         }
230         */
231         throw new ParseFailed(ret.toString(), region, input, gss);
232     }
233
234 }