00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <basix/source_track.hpp>
00014 #include <basix/literal.hpp>
00015 #include <basix/compound.hpp>
00016 #include <basix/system.hpp>
00017
00018 namespace mmx {
00019
00020 nat backtrace_depth= 8;
00021
00022 string repeated (const string& s, nat n);
00023 nat get_indentation (const string& s);
00024 string add_indentation (const string& s, int delta);
00025
00026
00027
00028
00029
00030 static vector< vector<string> > interactive_sources;
00031 static table< vector<string>, string > file_sources;
00032
00033 void
00034 store_interactive_number (nat n) {
00035 ASSERT (n <= N(interactive_sources), "input number out of range");
00036 interactive_sources= range (interactive_sources, 0, n);
00037 }
00038
00039 nat
00040 get_interactive_number (void) {
00041 return N(interactive_sources) ;
00042 }
00043
00044 void
00045 store_interactive_source (const string& data, nat n) {
00046 ASSERT (n <= get_interactive_number (), "input number out of range");
00047 vector<string> v= tokenize (data, "\n");
00048 if (n == get_interactive_number ()) interactive_sources << v;
00049 else interactive_sources[n]= v;
00050 }
00051
00052 string
00053 get_interactive_source (nat i) {
00054 ASSERT (i < N (interactive_sources), "source out of range");
00055 return recompose (interactive_sources[i], '\n');
00056 }
00057
00058 static string
00059 get_interactive_source (nat i, nat l) {
00060 ASSERT (i < N (interactive_sources), "source out of range");
00061 ASSERT (l < N (interactive_sources[i]), "source out of range");
00062 return interactive_sources[i][l];
00063 }
00064
00065 void
00066 store_file_source (const string& file_name, const string& data) {
00067 file_sources [file_name] = tokenize (data, "\n");
00068 }
00069
00070 string
00071 get_file_source (const string& file_name) {
00072 return recompose (file_sources [file_name], "\n");
00073 }
00074
00075 static string
00076 get_file_source (const string& file_name, nat line) {
00077 if (!file_sources->contains (file_name)) return "";
00078 ASSERT (line < N (read (file_sources, file_name)), "source out of range");
00079 return read (file_sources, file_name) [line];
00080 }
00081
00082 string
00083 get_source (const string& file_name, nat i) {
00084 if (file_name == "") return get_interactive_source (i);
00085 return get_file_source (file_name);
00086 }
00087
00088 string
00089 get_source (const string& file_name, nat i, nat line) {
00090 if (file_name == "") return get_interactive_source (i, line);
00091 return get_file_source (file_name, line);
00092 }
00093
00094
00095
00096
00097
00098 struct gen_eq_op {
00099 static generic name () { return generic ("gen_eq"); }
00100 static inline bool
00101 op (const generic& x, const generic& y) { return gen_eq (x, y); }
00102 static inline bool
00103 not_op (const generic& x, const generic& y) { return gen_neq (x, y); }
00104 static inline nat
00105 hash_op (const generic& x) { return gen_hash (x); }
00106 };
00107
00108 struct gen_eq_table {
00109 typedef gen_eq_op key_op;
00110 typedef equal_op val_op;
00111 };
00112
00113 table<source_location, generic, gen_eq_table>&
00114 source_locs () {
00115 static table<source_location, generic, gen_eq_table> t=
00116 table<source_location, generic, gen_eq_table> ();
00117 return t;
00118 }
00119
00120
00121
00122
00123 void
00124 source_insert (const generic& g, const source_location& l) {
00125 source_locs () [g] = l;
00126 }
00127
00128 void
00129 source_delete (const generic& g) {
00130 reset (source_locs (), g);
00131 }
00132
00133 generic
00134 source_link (const generic& g1, const generic& g2, const generic& kind) {
00135 (void) kind;
00136 table<source_location, generic, gen_eq_table>& t= source_locs ();
00137 if (!contains (t, g1) && contains (t, g2)) t[g1] = t[g2];
00138 return g1;
00139 }
00140
00141 generic
00142 source_assign (const generic& g1, const generic& g2) {
00143 source_location l= source_locate (g2);
00144 if (!is_nil (l)) source_insert (g1, l);
00145 return g1;
00146 }
00147
00148 generic
00149 source_extend (const generic& g1, const generic& g2) {
00150
00151 source_location l;
00152 source_locate (g1, l);
00153 source_locate (g2, l);
00154 source_delete (g1);
00155 source_delete (g2);
00156 l.obj = g1;
00157 source_insert (g1, l);
00158 return g1;
00159 }
00160
00161
00162
00163
00164
00165 void
00166 source_locate (const generic& g, source_location& l) {
00167
00168 source_location arg_l = l;
00169 if (source_locs () -> contains (g)) {
00170 source_location l1 = read (source_locs (), g);
00171 if (is_nil (l))
00172 l = l1;
00173 else
00174 if (!is_nil (l1)) {
00175 l.obj = l1.obj;
00176 if (l.file_name == l1.file_name && l.input_number == l1.input_number) {
00177 l.begin = min (l.begin, l1.begin);
00178 l.end = max (l.end, l1.end);
00179 }
00180
00181 }
00182 return;
00183 }
00184 if (is<compound> (g))
00185 for (nat i=0; i<N(g); i++)
00186 source_locate (g[i], l);
00187 l.obj = g;
00188 }
00189
00190 source_location
00191 source_locate (const generic& g) {
00192 source_location l;
00193 source_locate (g, l);
00194 return l;
00195 }
00196
00197
00198
00199
00200
00201 bool
00202 source_has_exact (const generic& g) {
00203 return (source_locs () -> contains (g));
00204 }
00205
00206 bool
00207 source_exists (const generic& g) {
00208 return !is_nil (source_locate (g));
00209 }
00210
00211 string
00212 source_file (const generic& g) {
00213 source_location l= source_locate (g);
00214 if (is_nil (l)) return "";
00215 else if (l.file_name == "")
00216 return "input[" * as_string (l.input_number + 1) * "]";
00217 else return l.file_name;
00218 }
00219
00220 int
00221 source_line (const generic& g, const bool& last) {
00222 source_location l= source_locate (g);
00223 if (is_nil (l)) return 0;
00224 else if (last) return l.end.line;
00225 else return l.begin.line;
00226 }
00227
00228 int
00229 source_column (const generic& g, const bool& last) {
00230 source_location l= source_locate (g);
00231 if (is_nil (l)) return 0;
00232 else if (last) return l.end.column;
00233 else return l.begin.column;
00234 }
00235
00236 string
00237 source_begin (const generic& g) {
00238 if (!source_exists (g)) return "Unknown location";
00239 return source_file (g) * ":" *
00240 as_string (source_line (g, false)) * ":" *
00241 as_string (source_column (g, false));
00242 }
00243
00244 string
00245 source_end (const generic& g) {
00246 if (!source_exists (g)) return "Unknown location";
00247 return source_file (g) * ":" *
00248 as_string (source_line (g, true)) * ":" *
00249 as_string (source_column (g, true));
00250 }
00251
00252 string
00253 source_string (const generic& g) {
00254 source_location l= source_locate (g);
00255 if (is_nil (l)) return "";
00256 else {
00257 string src= get_source (l.file_name, l.input_number);
00258 return src (l.begin.position, l.end.position);
00259 }
00260 }
00261
00262 string
00263 source_string_unindented (const generic& g) {
00264 source_location l= source_locate (g);
00265 if (is_nil (l)) return "";
00266 else {
00267 string src= get_source (l.file_name, l.input_number);
00268 string sub= src (l.begin.position, l.end.position);
00269 string bis= repeated (" ", l.begin.column) * sub;
00270 return add_indentation (bis, -((int) get_indentation (bis)));
00271 }
00272 }
00273
00274
00275
00276
00277
00278 static string
00279 underlined (const string& file_name, const nat& n,
00280 const source_position& b, const source_position& e)
00281 {
00282
00283
00284 nat j;
00285 string line;
00286 string sout;
00287
00288 line = get_source (file_name, n, b.line);
00289
00290 sout << line << "\n";
00291 for (j=0; j < b.column; ++j)
00292 sout << " ";
00293 if (b.line == e.line) {
00294 for (; j < e.column; ++j)
00295 sout << "~";
00296 }
00297 else {
00298 if (e.line == b.line+1 && e.column == 0)
00299 sout << "^";
00300 else {
00301 for (; j < N(line); ++j)
00302 sout << "~";
00303 sout << "\n";
00304 if (e.column == 0) {
00305 if (e.line - 1 > b.line + 1)
00306 sout << "...\n";
00307 line = get_source (file_name, n, e.line-1);
00308 sout << line << "\n";
00309 for (j=0; j < N(line); ++j)
00310 sout << "~";
00311 if (N(line) == 0)
00312 sout << "^";
00313 }
00314 else {
00315 if (e.line > b.line + 1)
00316 sout << "...\n";
00317 line = get_source (file_name, n, e.line);
00318 sout << line << "\n";
00319 for (j=0; j < e.column; ++j)
00320 sout << "~";
00321 }
00322 }
00323 }
00324 sout << "\n";
00325 return sout;
00326 }
00327
00328 string
00329 source_underlined (const generic& g) {
00330 source_location l= source_locate (g);
00331 if (is_nil (l)) return "";
00332 else return underlined (l.file_name, l.input_number, l.begin, l.end);
00333 }
00334
00335 string
00336 source_error (const string& msg, const generic& g) {
00337 mmerr << ">>> g= " << g << "\n";
00338 string s;
00339 source_location l= source_locate (g);
00340 if (is_nil (l) && is<literal> (g))
00341 s << "Inside " << literal_to_string (g) << ": ";
00342 else if (is_nil (l))
00343 s << "Unknown location: ";
00344 else
00345 s << strip_directory (source_file (g)) << ":"
00346 << as_string (l.begin.line + 1) << ":"
00347 << as_string (l.begin.column + 1) << ": ";
00348 s << msg << "\n"
00349 << source_underlined (g);
00350 return s;
00351 }
00352
00353 string
00354 backtrace (const generic& g) {
00355 if (has_trace (g))
00356 return backtrace (trace_pull (g)) * backtrace (trace_top (g));
00357 else return source_exception (as<exception> (g));
00358 }
00359
00360 string
00361 source_exception (const exception& e) {
00362 generic g= as<generic> (e);
00363 if (has_trace (g))
00364 return backtrace (trace_bottom (g, backtrace_depth));
00365 else {
00366 generic err= *e;
00367 if (is<literal> (err[1]))
00368 return source_error (literal_to_string (err[1]), err[N(err)-1]);
00369 else return source_error ("unknown", err[N(err)-1]);
00370 }
00371 }
00372
00373 }