LCOV - code coverage report
Current view: top level - atermpp/source - aterm_io_text.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 138 185 74.6 %
Date: 2020-07-04 00:44:36 Functions: 19 20 95.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Jan Friso Groote
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : 
      10             : #include "mcrl2/atermpp/aterm_io_text.h"
      11             : 
      12             : #include <fstream>
      13             : 
      14             : namespace atermpp
      15             : {
      16             : 
      17             : // utility functions
      18             : 
      19      211147 : static void write_string_with_escape_symbols(const std::string& s, std::ostream& os)
      20             : {
      21             :   // Check whether the string starts with a - or a number, or contains the symbols
      22             :   // \, ", (, ), [, ], comma, space, \t, \n or \r. If yes, the string will be
      23             :   // surrounded by quotes, and the symbols \, ", \t, \n, \r
      24             :   // will be preceded by an escape symbol.
      25             : 
      26      211147 :   char c = s[0];
      27      211147 :   bool contains_special_symbols = ((c =='-') || isdigit(c));
      28             : 
      29     1413040 :   for(std::string::const_iterator i=s.begin(); !contains_special_symbols && i!=s.end(); ++i)
      30             :   {
      31     1201893 :     if (*i=='\\' || *i=='"' || *i=='(' || *i==')' || *i=='[' || *i==']' || *i==',' || *i==' ' || *i=='\n' || *i=='\t' || *i=='\r')
      32             :     {
      33        6682 :       contains_special_symbols=true;
      34             :     }
      35             :   }
      36             : 
      37      211147 :   if (contains_special_symbols)
      38             :   {
      39             :     // This function symbol needs quotes.
      40        6682 :     os << "\"";
      41       20046 :     for(std::string::const_iterator i=s.begin(); i!=s.end(); ++i)
      42             :     {
      43             :       // We need to escape special characters.
      44       13364 :       switch (*i)
      45             :       {
      46           0 :         case '\\':
      47             :         case '"':
      48           0 :           os << "\\" << *i;
      49           0 :           break;
      50           0 :         case '\n':
      51           0 :           os << "\\n";
      52           0 :           break;
      53           0 :         case '\t':
      54           0 :           os << "\\t";
      55           0 :           break;
      56           0 :         case '\r':
      57           0 :           os << "\\r";
      58           0 :           break;
      59       13364 :         default:
      60       13364 :           os << *i;
      61       13364 :           break;
      62             :       }
      63             :     }
      64        6682 :     os << "\"";
      65             :   }
      66             :   else
      67             :   {
      68      204465 :     os << s;
      69             :   }
      70      211147 : }
      71             : 
      72             : // Public functions
      73             : 
      74       12510 : text_aterm_ostream::text_aterm_ostream(std::ostream& os, bool newline)
      75             :   : m_stream(os),
      76       12510 :     m_newline(newline)
      77       12510 : {}
      78             : 
      79       12510 : void text_aterm_ostream::put(const aterm& term)
      80             : {
      81       12510 :   write_term_line(term);
      82             : 
      83       12510 :   if (m_newline)
      84             :   {
      85           0 :     m_stream << "\n";
      86             :   }
      87       12510 : }
      88             : 
      89       10103 : text_aterm_istream::text_aterm_istream(std::istream& is)
      90       10103 :   : m_stream(is)
      91             : {
      92       10103 :   character = next_char();
      93       10103 : }
      94             : 
      95       10103 : aterm text_aterm_istream::get()
      96             : {
      97       10103 :   aterm term;
      98             : 
      99             :   try
     100             :   {
     101       10103 :     if (character != EOF)
     102             :     {
     103       10103 :       term = parse_aterm(character);
     104             :     }
     105             :   }
     106           0 :   catch (std::runtime_error& e)
     107             :   {
     108           0 :     throw std::runtime_error(e.what() + std::string("\n") + print_parse_error_position());
     109             :   }
     110             : 
     111             :   // Reset the parsing error buffers.
     112       10103 :   m_column = 0;
     113       10103 :   m_history.clear();
     114             : 
     115       10103 :   return term;
     116             : }
     117             : 
     118             : // Private functions
     119             : 
     120      222148 : void text_aterm_ostream::write_term_line(const aterm& t)
     121             : {
     122      222148 :   if (t.type_is_int())
     123             :   {
     124             :     // Write a single integer as is.
     125        2225 :     m_stream << atermpp::down_cast<aterm_int>(t).value();
     126             :   }
     127      219923 :   else if (t.type_is_list())
     128             :   {
     129             :     // A list l0...ln is formatted as [l0, ..., ln].
     130        8776 :     m_stream << "[";
     131        8776 :     const aterm_list& list = down_cast<aterm_list>(t);
     132       26299 :     for (aterm_list::const_iterator it = list.begin(); it != list.end(); ++it)
     133             :     {
     134       17523 :       if (it!=list.begin())
     135             :       {
     136        8750 :         m_stream << ",";
     137             :       }
     138       17523 :       write_term_line(*it);
     139             :     }
     140             : 
     141        8776 :     m_stream << "]";
     142             :   }
     143             :   else
     144             :   {
     145             :     // An aterm_appl f(t0, ..., tn) is written as f(t0, ..., tn)
     146      211147 :     assert(t.type_is_appl());
     147             : 
     148      422294 :     aterm_appl appl = m_transformer(down_cast<aterm_appl>(t));
     149             : 
     150      211147 :     write_string_with_escape_symbols(appl.function().name(), m_stream);
     151             : 
     152      211147 :     if (appl.function().arity() > 0)
     153             :     {
     154      114186 :       m_stream << "(";
     155      114186 :       write_term_line(appl[0]);
     156      192115 :       for (std::size_t i = 1; i < appl.function().arity(); i++)
     157             :       {
     158       77929 :         m_stream << ",";
     159       77929 :         write_term_line(appl[i]);
     160             :       }
     161      114186 :       m_stream << ")";
     162             :     }
     163             :   }
     164      222148 : }
     165             : 
     166      221061 : aterm text_aterm_istream::parse_aterm(int& character)
     167             : {
     168             :   // Parse the term.
     169      221061 :   switch (character)
     170             :   {
     171        6689 :     case '"':
     172             :     {
     173       13378 :       std::string function_name = parse_quoted_string(character);
     174        6689 :       return parse_aterm_appl(function_name, character);
     175             :     }
     176        8851 :     case '[':
     177             :     {
     178        8851 :       return parse_aterm_list(character, '[', ']');
     179             :     }
     180      205521 :     default:
     181             :     {
     182      205521 :       if (isdigit(character) || character == '-')
     183             :       {
     184         202 :         return parse_aterm_int(character);
     185             :       }
     186             : 
     187      410638 :       std::string function_symbol = parse_unquoted_string(character);
     188      205319 :       return parse_aterm_appl(function_symbol, character);
     189             :     }
     190             :   }
     191             : }
     192             : 
     193      212008 : aterm_appl text_aterm_istream::parse_aterm_appl(const std::string& function_name, int& character)
     194             : {
     195             :   // Parse the arguments.
     196      424016 :   aterm_list arguments = parse_aterm_list(character, '(', ')');
     197             : 
     198             :   // Wrap up this function application.
     199      424016 :   function_symbol symbol(function_name, arguments.size());
     200      424016 :   return m_transformer(aterm_appl(symbol, arguments.begin(), arguments.end()));
     201             : }
     202             : 
     203         202 : aterm_int text_aterm_istream::parse_aterm_int(int& character)
     204             : {
     205             :   std::array<char, 32> number;
     206         202 :   auto it = number.begin();
     207             : 
     208         202 :   if (character == '-')
     209             :   {
     210           0 :     *it = static_cast<char>(character);
     211           0 :     ++it;
     212           0 :     character = next_char(true, true);
     213             :   }
     214             : 
     215         862 :   while (isdigit(character) && it != number.end())
     216             :   {
     217         330 :     *it = static_cast<char>(character);
     218         330 :     ++it;
     219         330 :     character = next_char();
     220             :   }
     221             : 
     222         202 :   *it = '\0';
     223         202 :   return aterm_int(static_cast<std::size_t>(atol(number.data())));
     224             : }
     225             : 
     226      220859 : aterm_list text_aterm_istream::parse_aterm_list(int& character, char begin, char end)
     227             : {
     228      441718 :   aterm_list list;
     229             : 
     230             :   // A list is [t0, ..., tn] or surrounded by ().
     231      220859 :   if (character == begin)
     232             :   {
     233      123655 :     character = next_char(true, true);
     234      123655 :     if (character != end)
     235             :     {
     236      123646 :       list.push_front(parse_aterm(character));
     237             : 
     238      298270 :       while (character == ',')
     239             :       {
     240       87312 :         character = next_char(true, true);
     241       87312 :         list.push_front(parse_aterm(character));
     242             :       }
     243             : 
     244      123646 :       if (character != end)
     245             :       {
     246           0 :         throw std::runtime_error(std::string("Missing ") + end + " while parsing a list term");
     247             :       }
     248             :     }
     249             : 
     250      123655 :     character = next_char(true);
     251             :   }
     252             : 
     253      441718 :   return reverse(list);
     254             : }
     255             : 
     256             : 
     257           0 : std::string text_aterm_istream::print_parse_error_position()
     258             : {
     259           0 :   std::stringstream s;
     260           0 :   s << "Error occurred at line " << m_line << ", col " << m_column << " near: ";
     261           0 :   for(const auto& element : m_history)
     262             :   {
     263           0 :     s << element;
     264             :   }
     265           0 :   return s.str();
     266             : }
     267             : 
     268     1572524 : int text_aterm_istream::next_char(bool skip_whitespace, bool required)
     269             : {
     270     1572524 :   character = EOF;
     271             : 
     272           0 :   do
     273             :   {
     274             :     try
     275             :     {
     276             :       // In liblts_lts the exception bit is set, so we need to use exception to handle EOF.
     277     1572524 :       character = m_stream.get();
     278             :     }
     279           0 :     catch (std::ios::failure&)
     280             :     {
     281           0 :       return EOF;
     282             :     }
     283             : 
     284     1572524 :     if (character != EOF)
     285             :     {
     286     1562421 :       if (character == '\n')
     287             :       {
     288           0 :         m_line++;
     289           0 :         m_column = 0;
     290             :       }
     291             :       else
     292             :       {
     293     1562421 :         m_column++;
     294             :       }
     295             : 
     296     1562421 :       if (m_history.size() >= m_history_limit)
     297             :       {
     298             :         // If the history is full the first element must be removed.
     299     1068236 :         m_history.erase(m_history.begin());
     300             :       }
     301             : 
     302     1562421 :       m_history.emplace_back(character);
     303             :     }
     304       10103 :     else if (required)
     305             :     {
     306           0 :       throw std::runtime_error("Premature end of file while parsing.");
     307             :     }
     308             :   }
     309     1572524 :   while (isspace(character) && skip_whitespace);
     310             : 
     311             :   // The stream also returns a newline for the last symbol.
     312     1572524 :   return character == '\n' ? EOF : character;
     313             : }
     314             : 
     315        6689 : std::string text_aterm_istream::parse_quoted_string(int& character)
     316             : {
     317             :   // We need a buffer for printing and parsing.
     318        6689 :   std::string string;
     319             : 
     320        6689 :   assert(character == '"');
     321             : 
     322             :   // First obtain the first symbol after ".
     323        6689 :   character = next_char();
     324             : 
     325       33445 :   while (character != '"')
     326             :   {
     327       13378 :     switch (character)
     328             :     {
     329           0 :       case '\\':
     330           0 :         character = next_char(false, true);
     331           0 :         switch (character)
     332             :         {
     333           0 :           case 'n':
     334           0 :             string += '\n';
     335           0 :             break;
     336           0 :           case 'r':
     337           0 :             string += '\r';
     338           0 :             break;
     339           0 :           case 't':
     340           0 :             string += '\t';
     341           0 :             break;
     342           0 :           default:
     343           0 :             string += static_cast<char>(character);
     344           0 :             break;
     345             :         }
     346           0 :         break;
     347       13378 :       default:
     348       13378 :         string += static_cast<char>(character);
     349       13378 :         break;
     350             :     }
     351       13378 :     character = next_char(false, true);
     352             :   }
     353             : 
     354        6689 :   character = next_char(true, false);
     355        6689 :   return string;
     356             : }
     357             : 
     358      205319 : std::string text_aterm_istream::parse_unquoted_string(int& character)
     359             : {
     360      205319 :   std::string string;
     361             : 
     362      205319 :   if (character != '(')
     363             :   {
     364             :     // First parse the identifier
     365     4012777 :     while (character != '"' && character != '(' && character != ')' && character != ']'
     366     1245967 :       && character != ']' && character != ',' && character != ' ' && character != '\n'
     367     2606764 :       && character != '\t' && character != '\r' && character != EOF)
     368             :     {
     369     1200713 :       string += static_cast<char>(character);
     370     1200713 :       character = next_char(false);
     371             :     }
     372             :   }
     373             : 
     374      205319 :   return string;
     375             : }
     376             : 
     377           7 : void write_term_to_text_stream(const aterm& term, std::ostream& os)
     378             : {
     379           7 :   text_aterm_ostream(os) << term;
     380           7 : }
     381             : 
     382       10097 : aterm read_term_from_string(const std::string& s)
     383             : {
     384       20194 :   std::stringstream ss(s);
     385       20194 :   return  read_term_from_text_stream(ss);
     386             : }
     387             : 
     388       10103 : aterm read_term_from_text_stream(std::istream& is)
     389             : {
     390       10103 :   return text_aterm_istream(is).get();
     391             : }
     392             : 
     393             : 
     394       12503 : std::ostream& operator<<(std::ostream& os, const aterm& term)
     395             : {
     396       12503 :   text_aterm_ostream(os) << term;
     397       12503 :   return os;
     398             : }
     399             : 
     400         423 : } // namespace atermpp

Generated by: LCOV version 1.13