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 }