dumper.cc

Go to the documentation of this file.
00001 /*
00002    The lestes compiler suite
00003    Copyright (C) 2002, 2003, 2004, 2005 Miroslav Tichy
00004    Copyright (C) 2002, 2003, 2004, 2005 Petr Zika
00005    Copyright (C) 2002, 2003, 2004, 2005 Vojtech Hala
00006    Copyright (C) 2002, 2003, 2004, 2005 Jiri Kosina
00007    Copyright (C) 2002, 2003, 2004, 2005 Pavel Sanda
00008    Copyright (C) 2002, 2003, 2004, 2005 Jan Zouhar
00009    Copyright (C) 2002, 2003, 2004, 2005 Rudolf Thomas
00010 
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; version 2 of the License.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    See the full text of the GNU General Public License version 2, and
00021    the limitations in the file doc/LICENSE.
00022 
00023    By accepting the license the licensee waives any and all claims
00024    against the copyright holder(s) related in whole or in part to the
00025    work, its use, and/or the inability to use it.
00026  
00027  */
00028 #include <lestes/std/dumper.hh>
00029 #include <lestes/std/reflect.hh>
00030 #include <lestes/std/objectize.hh>
00031 #include <lestes/std/objectize_macros.hh>
00032 #include <lestes/std/map.hh>
00033 #include <lestes/std/set.hh>
00034 #include <lestes/std/list.hh>
00035 #include <lestes/std/pair.hh>
00036 #include <lestes/std/vector.hh>
00037 
00038 package(lestes);
00039 package(std);
00040 
00041 using ::std::endl;
00042 
00043 ::std::ostream & dumper::dump( ::std::ostream & output_to,
00044                 ptr<object> start_at, bool respect_barriers )
00045 {
00046         ptr<dumper> instance = new dumper( output_to, respect_barriers );
00047         instance->the_dump(start_at);
00048         return output_to;
00049 }
00050 
00051 void dumper::visit_object( ptr<object> o )
00052 {
00053         lassert(o);
00054         was_simple = false;
00055 }
00056 
00057 void dumper::visit_nodump()
00058 {
00059         stream << "<nondumpable />";
00060         was_simple = true;
00061 }
00062 
00063 void dumper::visit_lint( lint i )
00064 {
00065         stream << "<simple type=\"lint\" value=\"" << i << "\" />";
00066         was_simple = true;
00067 }
00068 
00069 void dumper::visit_ulint( ulint i )
00070 {
00071         stream << "<simple type=\"ulint\" value=\"" << i << "\" />";
00072         was_simple = true;
00073 }
00074 
00075 void dumper::visit_bool( bool i )
00076 {
00077         // ostream does not seem to support bool (or vice versa?)
00078         stream << "<simple type=\"bool\" value=\"" << (i ? "true" : "false") << "\" />";
00079         was_simple = true;
00080 }
00081 
00082 void dumper::visit_lstring( const lstring &i )
00083 {
00084         lstring tmp(i);
00085         lstring sought("<>&");
00086         lstring lt("&lt;");
00087         lstring gt("&gt;");
00088         lstring amp("&amp;");
00089         lstring::size_type mark = tmp.find_first_of(sought);
00090         if (mark != lstring::npos)
00091                 do {
00092                         switch (tmp[mark]) {
00093                         case '<':
00094                                 tmp.replace(mark, 1, lt);
00095                                 break;
00096                         case '>':
00097                                 tmp.replace(mark, 1, gt);
00098                                 break;
00099                         case '&':
00100                                 tmp.replace(mark, 1, amp);
00101                                 break;
00102                         }
00103                 } while ((mark = tmp.find_first_of(sought, mark+1)) != lstring::npos);
00104         stream << "<simple type=\"lstring\" value=\"" << tmp << "\" />";
00105         was_simple = true;
00106 }
00107 
00108 void dumper::visit_ucn_string( const ucn_string &i )
00109 {
00110         ucn_string tmp(i);
00111         ucn_string sought("\x3c\x3e\x26");
00112         ucn_string lt("\x26\x6c\x74\x3b");
00113         ucn_string gt("\x26\x67\x74\x3b");
00114         ucn_string amp("\x26\x61\x6d\x70\x3b");
00115         ucn_string::size_type mark = tmp.find_first_of(sought);
00116         if (mark != ucn_string::npos)
00117                 do {
00118                         switch (tmp[mark]) {
00119                         case 0x3c:
00120                                 tmp.replace(mark, 1, lt);
00121                                 break;
00122                         case 0x3e:
00123                                 tmp.replace(mark, 1, gt);
00124                                 break;
00125                         case 0x26:
00126                                 tmp.replace(mark, 1, amp);
00127                                 break;
00128                         }
00129                 } while ((mark = tmp.find_first_of(sought, mark+1)) != ucn_string::npos);
00130         stream << "<simple type=\"ucn_string\" value=\"" << tmp << "\" />";
00131         was_simple = true;
00132 }
00133 
00134 void dumper::try_enqueue( ptr<object> o, ptr<queue_type> queue, ptr<set_type> visited )
00135 {
00136         bool not_yet_visited = visited->insert(o).second;
00137         if (not_yet_visited)
00138                 queue->push_back(o);
00139 }
00140 
00141 void dumper::gc_mark()
00142 {
00143         dumper_visitor::gc_mark();
00144 }
00145 
00146 dumper::dumper( ::std::ostream &a_stream, bool a_respect_barriers )
00147         : dumper_visitor(), stream(a_stream), respect_barriers(a_respect_barriers)
00148 {}
00149 
00150 void dumper::the_dump( ptr<object> start_at )
00151 {
00152         ptr<queue_type> queue = queue_type::create();
00153         ptr<set_type> visited = set_type::create();
00154 
00155         stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00156                 "<dump xmlns=\"http://lestes.jikos.cz/schemas/dump\">" << endl;
00157         if (start_at) {
00158                 // if start_at is simple type, do not bother to run the algorithm :)
00159                 start_at->accept_dumper_visitor(this);
00160                 if (!was_simple) {
00161                         try_enqueue( start_at, queue, visited );
00162                 }
00163         } else {
00164                 stream << "<null />" << endl;
00165         }
00166         while ( !queue->empty() ) {
00167                 ptr<object> current = queue->front();
00168                 queue->pop_front();
00169                 // we do not enqueue null values
00170                 lassert(current);
00171 
00172                 bool at_barrier = current->dump_barrier_get();
00173 
00174                 ptr<reflection_list> refls = current->reflection_get();
00175                 lassert( refls );
00176 
00177                 stream << "<instance type=\"" << refls->back()->name_get() << "\""
00178                         " id=\"i_" << current->uid_get() << "\">" << endl;
00179                 ptr<field_list_list> fields = current->field_values_get();
00180                 field_list_list::iterator field_it = fields->begin();
00181                 for ( reflection_list::iterator refl_it = refls->begin();
00182                                 refl_it != refls->end(); ++refl_it ) {
00183 
00184                         ptr<class_reflection::field_metadata_list> metadata =
00185                                 (*refl_it)->field_metadata_get();
00186 
00187                         for (class_reflection::field_metadata_list::iterator
00188                                         meta_it = metadata->begin();
00189                                         meta_it != metadata->end();
00190                                         ++meta_it, ++field_it ) {
00191 
00192                                 // we must not run out of fields
00193                                 lassert( field_it != fields->end() );
00194 
00195                                 ulint item_no = 0;
00196                                 bool do_append_no = (*field_it)->size() > 1;
00197                                 for (value_list::iterator val_it = (*field_it)->begin();
00198                                                 val_it != (*field_it)->end();
00199                                                 ++val_it, ++item_no ) {
00200 
00201                                         stream << "<field name=\"" << (*meta_it)->first;
00202                                         if (do_append_no)
00203                                                 stream << item_no;
00204                                         stream << "\" type=\"" << (*meta_it)->second << "\""
00205                                                 " origin=\"" << (*refl_it)->name_get() << "\">";
00206                                         if (*val_it) {
00207                                                 (*val_it)->accept_dumper_visitor(this);
00208                                                 if (!was_simple) {
00209                                                         if (respect_barriers && at_barrier)
00210                                                                 stream << "<after-barrier />";
00211                                                         else {
00212                                                                 try_enqueue( *val_it, queue, visited );
00213                                                                 stream << "<pointer idref=\"i_" <<
00214                                                                         (*val_it)->uid_get() << "\" />";
00215                                                         }
00216                                                 }
00217                                         } else
00218                                                 stream << "<null />";
00219                                         stream << "</field>" << endl;
00220                                 }
00221                         }
00222                 }
00223 
00224                 // just an assert: there should not be any value lists left
00225                 lassert( field_it == fields->end() );
00226                 stream << "</instance>" << endl;
00227         };
00228         stream << "</dump>" << endl;
00229 }
00230 
00231 ::std::ostream & readable_dumper::dump( ::std::ostream & output_to,
00232                 ptr<object> start_at, bool respect_barriers )
00233 {
00234         ptr<readable_dumper> instance =
00235                 new readable_dumper( output_to, respect_barriers );
00236         instance->visited = set_type::create();
00237         instance->after_barrier = false;
00238         if (start_at) {
00239                 output_to << "<dump>" << endl;
00240                 start_at->accept_dumper_visitor(instance);
00241                 output_to << "</dump>" << endl;
00242         } else
00243                 output_to << "<null />" << endl;
00244         return output_to;
00245 }
00246 
00247 void readable_dumper::gc_mark()
00248 {
00249         visited.gc_mark();
00250         dumper_visitor::gc_mark();
00251 }
00252 
00253 void readable_dumper::follow( ptr<object> o )
00254 {
00255         ptr<reflection_list> refls = o->reflection_get();
00256         lassert( refls );
00257 
00258         bool already_visited = !(visited->insert(o).second);
00259         if (already_visited) {
00260                 stream << '<' << refls->back()->name_get() << 
00261                         " idref=\"i_" << o->uid_get() << "\" />" << endl;
00262                 return;
00263         }
00264         stream << '<' << refls->back()->name_get() << " id=\"i_" << o->uid_get() << "\">" << endl;
00265 
00266         bool at_barrier = o->dump_barrier_get();
00267 
00268         ptr<field_list_list> fields = o->field_values_get();
00269         field_list_list::iterator field_it = fields->begin();
00270         for ( reflection_list::iterator refl_it = refls->begin();
00271                         refl_it != refls->end(); ++refl_it ) {
00272 
00273                 ptr<class_reflection::field_metadata_list> metadata =
00274                         (*refl_it)->field_metadata_get();
00275 
00276                 for (class_reflection::field_metadata_list::iterator
00277                                 meta_it = metadata->begin();
00278                                 meta_it != metadata->end();
00279                                 ++meta_it, ++field_it ) {
00280 
00281                         // we must not run out of fields
00282                         lassert( field_it != fields->end() );
00283 
00284                         ulint item_no = 0;
00285                         bool do_append_no = (*field_it)->size() > 1;
00286                         for (value_list::iterator val_it = (*field_it)->begin();
00287                                         val_it != (*field_it)->end(); ++val_it, ++item_no ) {
00288                                 stream << '<' << (*meta_it)->first;
00289                                 if (do_append_no)
00290                                         stream << item_no;
00291                                 stream << " type=\"" << (*meta_it)->second << "\""
00292                                         " origin=\"" << (*refl_it)->name_get() << "\">" <<
00293                                         endl;
00294                                 if (*val_it) {
00295                                         if (respect_barriers && at_barrier)
00296                                                 after_barrier = true;
00297                                         (*val_it)->accept_dumper_visitor(this);
00298                                         after_barrier = false;
00299                                 } else
00300                                         stream << "<null />" << endl;
00301                                 stream << "</" << (*meta_it)->first;
00302                                 if (do_append_no)
00303                                         stream << item_no;
00304                                 stream << '>' << endl;
00305                         }
00306                 }
00307         }
00308 
00309         // just an assert: there should not be any value lists left
00310         lassert( field_it == fields->end() );
00311 
00312         stream << "</" << refls->back()->name_get() << '>' << endl;
00313 }
00314 
00315 readable_dumper::readable_dumper( ::std::ostream &a_stream, bool a_respect_barriers )
00316         : dumper_visitor(), stream(a_stream), respect_barriers(a_respect_barriers)
00317 {}
00318 
00319 void readable_dumper::visit_object( ptr<object> o )
00320 {
00321         if (after_barrier)
00322                 stream << "<after-barrier />" << endl;
00323         else
00324                 follow(o);
00325 }
00326 
00327 void readable_dumper::visit_nodump()
00328 {
00329         stream << "<nondumpable />" << endl;
00330 }
00331 
00332 void readable_dumper::visit_lint( lint i )
00333 {
00334         stream << "<lint>" << i << "</lint>" << endl;
00335 }
00336 
00337 void readable_dumper::visit_ulint( ulint i )
00338 {
00339         stream << "<ulint>" << i << "</ulint>" << endl;
00340 }
00341 
00342 void readable_dumper::visit_bool( bool i )
00343 {
00344         // ostream does not seem to support bool, it would cast to int or something
00345         stream << "<bool>" << (i ? "true" : "false") << "</bool>" << endl;
00346 }
00347 
00348 void readable_dumper::visit_lstring( const lstring &i )
00349 {
00350         lstring tmp(i);
00351         lstring sought("<>&");
00352         lstring lt("&lt;");
00353         lstring gt("&gt;");
00354         lstring amp("&amp;");
00355         lstring::size_type mark = tmp.find_first_of(sought);
00356         if (mark != lstring::npos)
00357                 do {
00358                         switch (tmp[mark]) {
00359                         case '<':
00360                                 tmp.replace(mark, 1, lt);
00361                                 break;
00362                         case '>':
00363                                 tmp.replace(mark, 1, gt);
00364                                 break;
00365                         case '&':
00366                                 tmp.replace(mark, 1, amp);
00367                                 break;
00368                         }
00369                 } while ((mark = tmp.find_first_of(sought, mark+1)) != lstring::npos);
00370         stream << "<lstring>" << tmp << "</lstring>" << endl;
00371 }
00372 
00373 void readable_dumper::visit_ucn_string( const ucn_string &i )
00374 {
00375         ucn_string tmp(i);
00376         ucn_string sought("\x3c\x3e\x26");
00377         ucn_string lt("\x26\x6c\x74\x3b");
00378         ucn_string gt("\x26\x67\x74\x3b");
00379         ucn_string amp("\x26\x61\x6d\x70\x3b");
00380         ucn_string::size_type mark = tmp.find_first_of(sought);
00381         if (mark != ucn_string::npos)
00382                 do {
00383                         switch (tmp[mark]) {
00384                         case 0x3c:
00385                                 tmp.replace(mark, 1, lt);
00386                                 break;
00387                         case 0x3e:
00388                                 tmp.replace(mark, 1, gt);
00389                                 break;
00390                         case 0x26:
00391                                 tmp.replace(mark, 1, amp);
00392                                 break;
00393                         }
00394                 } while ((mark = tmp.find_first_of(sought, mark+1)) != ucn_string::npos);
00395         stream << "<ucn_string>" << tmp << "</ucn_string>" << endl;
00396 }
00397 
00398 end_package(std);
00399 end_package(lestes);

Generated on Mon Feb 12 18:22:33 2007 for lestes by doxygen 1.5.1-20070107