LCOV - code coverage report
Current view: top level - data/source/detail/rewrite - jittyc.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 1245 1502 82.9 %
Date: 2024-04-21 03:44:01 Functions: 79 87 90.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Muck van Weerdenburg
       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             : /// \file jittyc.cpp
      10             : 
      11             : #include "mcrl2/data/detail/rewrite.h" // Required for MCRL2_JITTTYC_AVAILABLE.
      12             : 
      13             : #ifdef MCRL2_ENABLE_JITTYC
      14             : 
      15             : #define NAME "rewr_jittyc"
      16             : 
      17             : #include <unistd.h>
      18             : #include <sys/stat.h>
      19             : #include "mcrl2/utilities/basename.h"
      20             : #include "mcrl2/utilities/stopwatch.h"
      21             : #include "mcrl2/atermpp/algorithm.h"
      22             : #include "mcrl2/atermpp/detail/aterm_list_implementation.h"
      23             : #include "mcrl2/data/detail/rewrite/jittyc.h"
      24             : #include "mcrl2/data/detail/rewrite/jitty_jittyc.h"
      25             : #include "mcrl2/data/replace.h"
      26             : 
      27             : #ifdef MCRL2_DISPLAY_REWRITE_STATISTICS
      28             : #include "mcrl2/data/detail/rewrite_statistics.h"
      29             : #endif
      30             : 
      31             : using namespace mcrl2::core;
      32             : using namespace mcrl2::core::detail;
      33             : using namespace atermpp;
      34             : using namespace mcrl2::log;
      35             : 
      36             : namespace mcrl2
      37             : {
      38             : namespace data
      39             : {
      40             : namespace detail
      41             : {
      42             : 
      43             : // Some compilers can only deal with a limited number of nested curly brackets. 
      44             : // This limit can be increased by using -fbracket-depth=C where C is a new constant
      45             : // value. By default this value C often appears to be 256. But not all compilers 
      46             : // recognize -fbracket-depth=C, making its use unreliable and therefore not advisable.
      47             : // In order to generate the these auxiliary code fragments, we need to recall 
      48             : // what the template and data parameters of the current process are. 
      49             : 
      50             : class bracket_level_data
      51             : {
      52             :   public:
      53             :     const std::size_t MCRL2_BRACKET_NESTING_LEVEL=250;  // Some compilers limit the nesting to 256 brackets.
      54             :                                                         // This guarantees that we will not use more. 
      55             :     std::size_t bracket_nesting_level;
      56             :     std::string current_template_parameters;
      57             :     std::stack< std::string > current_data_parameters;
      58             :     std::stack< std::string > current_data_arguments;
      59             : 
      60         897 :     bracket_level_data()
      61         897 :      : bracket_nesting_level(0)
      62         897 :     {}
      63             : };
      64             : 
      65             : /// This function returns the variables that occur in a complex subexpression within f.
      66             : /// For instance in f(n+1,m) it returns {n}. In m+f(n1+1,n2) it returns {n1}. 
      67             : /// The effect is that such variables n, and n1, must be in normalform, before evaluation.
      68             : /// This is required for the template structure of the compiling rewriter. 
      69        5444 : static void find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(
      70             :                    const data_expression& f,
      71             :                    const data_expression& e,
      72             :                    std::set <variable>& result)
      73             : {
      74        5444 :   if (is_function_symbol(e))
      75             :   {
      76        2267 :     return;
      77             :   }
      78        3177 :   else if (is_variable(e))
      79             :   {
      80        1818 :     return;
      81             :   }
      82        1359 :   else if (is_abstraction(e))
      83             :   {
      84          44 :     const abstraction& abstr = down_cast<abstraction>(e);
      85          44 :     std::set<variable> intermediate_result;
      86          44 :     find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, abstr.body(), intermediate_result);
      87             :     // Remove the bound variables.
      88         122 :     for(const variable& v: abstr.variables())
      89             :     {
      90          78 :       intermediate_result.erase(v);
      91             :     }
      92          44 :     result.insert(intermediate_result.begin(), intermediate_result.end());
      93             : 
      94          44 :     return;
      95          44 :   }
      96        1315 :   else if (is_where_clause(e))
      97             :   {
      98           0 :     const where_clause& where = down_cast<where_clause>(e);
      99           0 :     std::set<variable> intermediate_result;
     100           0 :     find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, where.body(), intermediate_result);
     101           0 :     result.insert(intermediate_result.begin(), intermediate_result.end());
     102           0 :     for(const assignment_expression& ass: where.declarations())
     103             :     {
     104           0 :       const assignment& ass1= atermpp::down_cast<assignment>(ass);
     105           0 :       intermediate_result.erase(ass1.lhs());
     106           0 :       find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, ass1.rhs(), intermediate_result);
     107             :     }
     108           0 :     result.insert(intermediate_result.begin(), intermediate_result.end());
     109             : 
     110           0 :     return;
     111           0 :   }
     112             :   else
     113             :   {
     114        1315 :     assert(is_application(e));
     115             :     // e has the shape application(head,t1,...,tn)
     116        1315 :     const application& appl = down_cast<application>(e);
     117        1315 :     const std::size_t arity = recursive_number_of_args(appl);
     118             : 
     119        1315 :     if (get_nested_head(e)==f)
     120             :     {
     121        1049 :       for(std::size_t i=0; i<arity; i++)   
     122             :       {
     123         692 :         const data_expression arg=get_argument_of_higher_order_term(appl, i);
     124         692 :         if (is_variable(arg))
     125             :         {
     126             :           // if the argument is a single variable, it is ignored.
     127             :         }
     128             :         else 
     129             :         {
     130         180 :           std::set<variable> variables_in_arg=find_free_variables(arg);
     131         180 :           result.insert(variables_in_arg.begin(), variables_in_arg.end());
     132         180 :         }
     133         692 :       }
     134             :       
     135             :     }
     136             :     else
     137             :     {
     138             :       // Traverse all subexpressions for occurrences of variables. 
     139         958 :       const data_expression& head = appl.head();
     140         958 :       find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, head, result);
     141        2732 :       for(const data_expression& arg: appl)
     142             :       {
     143        1774 :         find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, arg, result);
     144             :       }
     145             :     }
     146             :   }
     147             : 
     148        1315 :   return;
     149             : }
     150             : 
     151             : 
     152        2668 : static std::set<variable> find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression(
     153             :                    const data_expression& f,
     154             :                    const data_expression& e)
     155             : {
     156        2668 :   std::set <variable> result;
     157        2668 :   find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression_helper(f, e, result); 
     158        2668 :   return result;
     159           0 : }
     160             : 
     161             : 
     162             : typedef atermpp::term_list<variable_list> variable_list_list;
     163             : 
     164        2668 : static std::vector<bool> dep_vars(const data_equation& eqn)
     165             : {
     166        2668 :   std::vector<bool> result(recursive_number_of_args(eqn.lhs()), true);
     167        2668 :   std::set<variable> condition_vars = find_free_variables(eqn.condition());
     168             :   std::set<variable> variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression = 
     169        2668 :                    find_variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression(get_nested_head(eqn.lhs()),eqn.rhs());
     170        2668 :   double_variable_traverser<data::variable_traverser> lhs_doubles;
     171        2668 :   double_variable_traverser<data::variable_traverser> rhs_doubles;
     172        2668 :   lhs_doubles.apply(eqn.lhs());
     173        2668 :   rhs_doubles.apply(eqn.rhs());
     174             : 
     175        8035 :   for (std::size_t i = 0; i < result.size(); ++i)
     176             :   {
     177        5367 :     const data_expression& arg_i = get_argument_of_higher_order_term(atermpp::down_cast<application>(eqn.lhs()), i);
     178        5367 :     if (is_variable(arg_i))
     179             :     {
     180        2462 :       const variable& v = down_cast<variable>(arg_i);
     181        2462 :       if (condition_vars.count(v) == 0 && 
     182        2298 :           lhs_doubles.result().count(v) == 0 && 
     183        6120 :           rhs_doubles.result().count(v) == 0 &&
     184        1360 :           variables_in_the_scope_of_main_function_symbol_in_a_complex_subexpression.count(v) == 0)
     185             :       {
     186        1360 :         result[i] = false;
     187             :       }
     188             :     }
     189             :   }
     190        5336 :   return result;
     191        2668 : }
     192             : 
     193          10 : static std::size_t calc_max_arity(const function_symbol_vector& symbols)
     194             : {
     195          10 :   std::size_t max_arity = 0;
     196         825 :   for (const function_symbol& f: symbols)
     197             :   {
     198         815 :     std::size_t arity = getArity(f);
     199         815 :     max_arity = std::max(max_arity, arity);
     200             :   }
     201             : 
     202          10 :   return max_arity;
     203             : }
     204             : 
     205             : 
     206             : ///
     207             : /// \brief arity_is_allowed yields true if the function indicated by the function index can
     208             : ///        legitemately be used with a arguments. A function f:D1x...xDn->D can be used with 0 and
     209             : ///        n arguments. A function f:(D1x...xDn)->(E1x...Em)->F can be used with 0, n, and n+m
     210             : ///        arguments.
     211             : /// \param s A function sort
     212             : /// \param a The desired number of arguments
     213             : /// \return A boolean indicating whether a term of sort s applied to a arguments is a valid term.
     214             : ///
     215        7405 : static bool arity_is_allowed(const sort_expression& s, const std::size_t a)
     216             : {
     217        7405 :   if (a == 0)
     218             :   {
     219        3565 :     return true;
     220             :   }
     221        3840 :   if (is_function_sort(s))
     222             :   {
     223        3840 :     const function_sort& fs = atermpp::down_cast<function_sort>(s);
     224        3840 :     std::size_t n = fs.domain().size();
     225        3840 :     return n <= a && arity_is_allowed(fs.codomain(), a - n);
     226             :   }
     227           0 :   return false;
     228             : }
     229             : 
     230        8418 : void RewriterCompilingJitty::term2seq(const data_expression& t, match_tree_list& s, std::size_t *var_cnt, const bool omit_head)
     231             : {
     232        8418 :   if (is_function_symbol(t))
     233             :   {
     234        1683 :     const function_symbol f(t);
     235        1683 :     s.push_front(match_tree_F(f,dummy,dummy));
     236        1683 :     s.push_front(match_tree_D(dummy,0));
     237        1683 :     return;
     238        1683 :   }
     239             : 
     240        6735 :   if (is_variable(t))
     241             :   {
     242        4992 :     const variable v(t);
     243        4992 :     match_tree store = match_tree_S(v,dummy);
     244             : 
     245        4992 :     if (std::find(s.begin(),s.end(),store) != s.end())
     246             :     {
     247         524 :       s.push_front(match_tree_M(v,dummy,dummy));
     248             :     }
     249             :     else
     250             :     {
     251        4468 :       (*var_cnt)++;
     252        4468 :       s.push_front(store);
     253             :     }
     254        4992 :     return;
     255        4992 :   }
     256             : 
     257        1743 :   assert(is_application(t));
     258        1743 :   const application ta(t);
     259        1743 :   std::size_t arity = ta.size();
     260             : 
     261        1743 :   if (is_application(ta.head()))
     262             :   {
     263           0 :     term2seq(ta.head(),s,var_cnt,omit_head);
     264           0 :     s.push_front(match_tree_N(dummy,0));
     265             :   }
     266        1743 :   else if (!omit_head)
     267             :   {
     268             :     {
     269        1591 :       s.push_front(match_tree_F(function_symbol(ta.head()),dummy,dummy));
     270             :     }
     271             :   }
     272             : 
     273        1743 :   std::size_t j=1;
     274        4856 :   for (const data_expression& u: ta)
     275             :   {
     276        3113 :     term2seq(u,s,var_cnt,false);
     277        3113 :     if (j<arity)
     278             :     {
     279        1370 :       s.push_front(match_tree_N(dummy,0));
     280             :     }
     281        3113 :     ++j;
     282             :   }
     283             : 
     284        1743 :   if (!omit_head)
     285             :   {
     286        1591 :     s.push_front(match_tree_D(dummy,0));
     287             :   }
     288        1743 : }
     289             : 
     290        2756 : static variable_or_number_list get_used_vars(const data_expression& t)
     291             : {
     292        2756 :   std::set <variable> vars = find_free_variables(t);
     293        5512 :   return variable_or_number_list(vars.begin(),vars.end());
     294        2756 : }
     295             : 
     296        2668 : match_tree_list RewriterCompilingJitty::create_sequence(const data_equation& rule, std::size_t* var_cnt)
     297             : {
     298        2668 :   const data_expression lhs_inner = rule.lhs();
     299        2668 :   const data_expression cond = rule.condition();
     300        2668 :   const data_expression rslt = rule.rhs();
     301        2668 :   match_tree_list rseq;
     302             : 
     303        2668 :   if (!is_function_symbol(lhs_inner))
     304             :   {
     305        2668 :     const application lhs_innera(lhs_inner);
     306        2668 :     std::size_t lhs_arity = lhs_innera.size();
     307             : 
     308        2668 :     if (is_application(lhs_innera.head()))
     309             :     {
     310         152 :       term2seq(lhs_innera.head(),rseq,var_cnt,true);
     311         152 :       rseq.push_front(match_tree_N(dummy,0));
     312             :     }
     313             : 
     314        2668 :     std::size_t j=1;
     315        7821 :     for (application::const_iterator i=lhs_innera.begin(); i!=lhs_innera.end(); ++i,++j)
     316             :     {
     317        5153 :       term2seq(*i,rseq,var_cnt,false);
     318        5153 :       if (j<lhs_arity)
     319             :       {
     320        2485 :         rseq.push_front(match_tree_N(dummy,0));
     321             :       }
     322             :     }
     323        2668 :   }
     324             : 
     325        2668 :   if (cond==sort_bool::true_())
     326             :   {
     327        2580 :     rseq.push_front(match_tree_Re(rslt,get_used_vars(rslt)));
     328             :   }
     329             :   else
     330             :   {
     331          88 :     rseq.push_front(match_tree_CRe(cond,rslt, get_used_vars(cond), get_used_vars(rslt)));
     332             :   }
     333             : 
     334        5336 :   return reverse(rseq);
     335        2668 : }
     336             : 
     337             : 
     338       34020 : static match_tree_list_list_list add_to_stack(const match_tree_list_list_list& stack, const match_tree_list_list& seqs, match_tree_Re& r, match_tree_list& cr)
     339             : {
     340       34020 :   if (stack.empty())
     341             :   {
     342       13290 :     return stack;
     343             :   }
     344             : 
     345       20730 :   match_tree_list_list l;
     346       20730 :   match_tree_list_list h = stack.front();
     347             : 
     348       34195 :   for (const match_tree_list& e: seqs)
     349             :   {
     350       13465 :     if (e.front().isD())
     351             :     {
     352        4680 :       l.push_front(e.tail());
     353             :     }
     354        8785 :     else if (e.front().isN())
     355             :     {
     356        4815 :       h.push_front(e.tail());
     357             :     }
     358        3970 :     else if (e.front().isRe())
     359             :     {
     360        3870 :       r = match_tree_Re(e.front());
     361             :     }
     362             :     else
     363             :     {
     364         100 :       cr.push_front(e.front());
     365             :     }
     366             :   }
     367             : 
     368       20730 :   match_tree_list_list_list result=add_to_stack(stack.tail(),l,r,cr);
     369       20730 :   result.push_front(h);
     370       20730 :   return result;
     371       20730 : }
     372             : 
     373        7879 : static void add_to_build_pars(build_pars& pars, const match_tree_list_list& seqs, match_tree_Re& r, match_tree_list& cr)
     374             : {
     375        7879 :   match_tree_list_list l;
     376             : 
     377       20468 :   for (const match_tree_list& e: seqs)
     378             :   {
     379       12589 :     if (e.front().isD() || e.front().isN())
     380             :     {
     381        2031 :       l.push_front(e);
     382             :     }
     383       10558 :     else if (e.front().isS())
     384             :     {
     385        5556 :       pars.Slist.push_front(e);
     386             :     }
     387        5002 :     else if (e.front().isMe())     // M should not appear at the head of a seq
     388             :     {
     389        1198 :       pars.Mlist.push_front(e);
     390             :     }
     391        3804 :     else if (e.front().isF())
     392             :     {
     393        3804 :       pars.Flist.push_front(e);
     394             :     }
     395           0 :     else if (e.front().isRe())
     396             :     {
     397           0 :       r = e.front();
     398             :     }
     399             :     else
     400             :     {
     401           0 :       cr.push_front(e.front());
     402             :     }
     403             :   }
     404             : 
     405        7879 :   pars.stack = add_to_stack(pars.stack,l,r,cr);
     406        7879 : }
     407             : 
     408        4213 : static variable createFreshVar(const sort_expression& sort, std::size_t* i)
     409             : {
     410        8426 :   return data::variable("@var_" + std::to_string((*i)++), sort);
     411             : }
     412             : 
     413        5556 : match_tree_list RewriterCompilingJitty::subst_var(const match_tree_list& l,
     414             :                                                   const variable& old,
     415             :                                                   const variable& new_val,
     416             :                                                   const std::size_t num,
     417             :                                                   const mutable_map_substitution<>& substs)
     418             : {
     419        5556 :   match_tree_vector result;
     420       32949 :   for(match_tree_list::const_iterator i=l.begin(); i!=l.end(); ++i)
     421             :   {
     422       27393 :     match_tree head=*i;
     423       27393 :     if (head.isM())
     424             :     {
     425         674 :       const match_tree_M headM(head);
     426         674 :       if (headM.match_variable()==old)
     427             :       {
     428         532 :         assert(headM.true_tree()==dummy);
     429         532 :         assert(headM.false_tree()==dummy);
     430         532 :         head = match_tree_Me(new_val,num);
     431             :       }
     432         674 :     }
     433       26719 :     else if (head.isCRe())
     434             :     {
     435         244 :       const match_tree_CRe headCRe(head);
     436         244 :       variable_or_number_list l = headCRe.variables_condition(); // This is a list with variables and aterm_ints.
     437         244 :       variable_or_number_list m ;                                // Idem.
     438         702 :       for (; !l.empty(); l=l.tail())
     439             :       {
     440         458 :         if (l.front()==old)
     441             :         {
     442         172 :           m.push_front(atermpp::aterm_int(num));
     443             :         }
     444             :         else
     445             :         {
     446         286 :           m.push_front(l.front());
     447             :         }
     448             :       }
     449         244 :       l = headCRe.variables_result();
     450         244 :       variable_or_number_list n;
     451         786 :       for (; !l.empty(); l=l.tail())
     452             :       {
     453         542 :         if (l.front()==old)
     454             :         {
     455         146 :           n.push_front(atermpp::aterm_int(num));
     456             :         }
     457             :         else
     458             :         {
     459         396 :           n.push_front(l.front());
     460             :         }
     461             :       }
     462         488 :       head = match_tree_CRe(replace_variables_capture_avoiding(headCRe.condition(),substs),
     463         732 :                             replace_variables_capture_avoiding(headCRe.result(),substs),m, n);
     464         244 :     }
     465       26475 :     else if (head.isRe())
     466             :     {
     467        5312 :       const match_tree_Re& headRe(head);
     468        5312 :       variable_or_number_list l = headRe.variables();
     469        5312 :       variable_or_number_list m ;
     470       14108 :       for (; !l.empty(); l=l.tail())
     471             :       {
     472        8796 :         if (l.front()==old)
     473             :         {
     474        3292 :           m.push_front(atermpp::aterm_int(num));
     475             :         }
     476             :         else
     477             :         {
     478        5504 :           m.push_front(l.front());
     479             :         }
     480             :       }
     481        5312 :       head = match_tree_Re(replace_variables_capture_avoiding(headRe.result(),substs),m);
     482        5312 :     }
     483       27393 :     result.push_back(head);
     484       27393 :   }
     485       11112 :   return match_tree_list(result.begin(),result.end());
     486        5556 : }
     487             : 
     488             : static std::vector < std::size_t> treevars_usedcnt;
     489             : 
     490        3900 : static void inc_usedcnt(const variable_or_number_list& l)
     491             : {
     492        7634 :   for (const variable_or_number& v: l)
     493             :   {
     494        3734 :     if (v.type_is_int())
     495             :     {
     496        3734 :       treevars_usedcnt[down_cast<aterm_int>(v).value()]++;
     497             :     }
     498             :   }
     499        3900 : }
     500             : 
     501       19036 : match_tree RewriterCompilingJitty::build_tree(build_pars pars, std::size_t i)
     502             : {
     503       19036 :   if (!pars.Slist.empty())
     504             :   {
     505        4213 :     match_tree_list l;
     506        4213 :     match_tree_list_list m;
     507             : 
     508        4213 :     std::size_t k = i;
     509        4213 :     const variable v = createFreshVar(match_tree_S(pars.Slist.front().front()).target_variable().sort(),&i);
     510        4213 :     treevars_usedcnt[k] = 0;
     511             : 
     512        9769 :     for (; !pars.Slist.empty(); pars.Slist=pars.Slist.tail())
     513             :     {
     514        5556 :       match_tree_list e = pars.Slist.front();
     515             : 
     516        5556 :       mutable_map_substitution<> sigma;
     517        5556 :       sigma[match_tree_S(e.front()).target_variable()]=v;
     518       11112 :       e = subst_var(e,
     519       11112 :                     match_tree_S(e.front()).target_variable(),
     520             :                     v,
     521             :                     k,
     522        5556 :                     sigma);
     523             : 
     524        5556 :       l.push_front(e.front());
     525        5556 :       m.push_front(e.tail());
     526        5556 :     }
     527             : 
     528        4213 :     match_tree_Re r;
     529        4213 :     match_tree ret;
     530        4213 :     match_tree_list readies;
     531             : 
     532        4213 :     pars.stack = add_to_stack(pars.stack,m,r,readies);
     533             : 
     534        4213 :     if (!r.is_defined())
     535             :     {
     536        2219 :       match_tree tree = build_tree(pars,i);
     537        2311 :       for (match_tree_list::const_iterator i=readies.begin(); i!=readies.end(); ++i)
     538             :       {
     539          92 :         match_tree_CRe t(*i);
     540          92 :         inc_usedcnt(t.variables_condition());
     541          92 :         inc_usedcnt(t.variables_result());
     542          92 :         tree = match_tree_C(t.condition(),match_tree_R(t.result()),tree);
     543          92 :       }
     544        2219 :       ret = tree;
     545        2219 :     }
     546             :     else
     547             :     {
     548             : 
     549        1994 :       inc_usedcnt(r.variables());
     550        1994 :       ret = match_tree_R(r.result());
     551             :     }
     552             : 
     553        4213 :     if ((treevars_usedcnt[k] > 0) || ((k == 0) && ret.isR()))
     554             :     {
     555        3217 :        return match_tree_S(v,ret);
     556             :     }
     557             :     else
     558             :     {
     559         996 :        return ret;
     560             :     }
     561        4213 :   }
     562       14823 :   else if (!pars.Mlist.empty())
     563             :   {
     564        1198 :     match_tree_Me M(pars.Mlist.front().front());
     565             : 
     566        1198 :     match_tree_list_list l;
     567        1198 :     match_tree_list_list m;
     568        2396 :     for (; !pars.Mlist.empty(); pars.Mlist=pars.Mlist.tail())
     569             :     {
     570        1198 :       if (M==pars.Mlist.front().front())
     571             :       {
     572        1198 :         l.push_front(pars.Mlist.front().tail());
     573             :       }
     574             :       else
     575             :       {
     576           0 :         m.push_front(pars.Mlist.front());
     577             :       }
     578             :     }
     579        1198 :     pars.Mlist = m;
     580             : 
     581        1198 :     match_tree true_tree,false_tree;
     582        1198 :     match_tree_Re r ;
     583        1198 :     match_tree_list readies;
     584             : 
     585        1198 :     match_tree_list_list_list newstack = add_to_stack(pars.stack,l,r,readies);
     586             : 
     587        1198 :     false_tree = build_tree(pars,i);
     588             : 
     589        1198 :     if (!r.is_defined())
     590             :     {
     591         279 :       pars.stack = newstack;
     592         279 :       true_tree = build_tree(pars,i);
     593         279 :       for (; !readies.empty(); readies=readies.tail())
     594             :       {
     595           0 :         match_tree_CRe t(readies.front());
     596           0 :         inc_usedcnt(t.variables_condition());
     597           0 :         inc_usedcnt(t.variables_result());
     598           0 :         true_tree = match_tree_C(t.condition(), match_tree_R(t.result()),true_tree);
     599           0 :       }
     600             :     }
     601             :     else
     602             :     {
     603         919 :       inc_usedcnt(r.variables());
     604         919 :       true_tree = match_tree_R(r.result());
     605             :     }
     606             : 
     607        1198 :     if (true_tree==false_tree)
     608             :     {
     609           0 :        return true_tree;
     610             :     }
     611             :     else
     612             :     {
     613        1198 :       treevars_usedcnt[M.variable_index()]++;
     614        1198 :       return match_tree_M(M.match_variable(),true_tree,false_tree);
     615             :     }
     616        1198 :   }
     617       13625 :   else if (!pars.Flist.empty())
     618             :   {
     619        3214 :     match_tree_list F = pars.Flist.front();
     620        3214 :     match_tree true_tree,false_tree;
     621             : 
     622        3214 :     match_tree_list_list newupstack = pars.upstack;
     623        3214 :     match_tree_list_list l;
     624             : 
     625        9518 :     for (; !pars.Flist.empty(); pars.Flist=pars.Flist.tail())
     626             :     {
     627        6304 :       if (pars.Flist.front().front()==F.front())
     628             :       {
     629        3958 :         newupstack.push_front(pars.Flist.front().tail());
     630             :       }
     631             :       else
     632             :       {
     633        2346 :         l.push_front(pars.Flist.front());
     634             :       }
     635             :     }
     636             : 
     637        3214 :     pars.Flist = l;
     638        3214 :     false_tree = build_tree(pars,i);
     639        3214 :     pars.Flist = match_tree_list_list();
     640        3214 :     pars.upstack = newupstack;
     641        3214 :     true_tree = build_tree(pars,i);
     642             : 
     643        3214 :     if (true_tree==false_tree)
     644             :     {
     645           0 :       return true_tree;
     646             :     }
     647             :     else
     648             :     {
     649        3214 :       return match_tree_F(match_tree_F(F.front()).function(),true_tree,false_tree);
     650             :     }
     651        3214 :   }
     652       10411 :   else if (!pars.upstack.empty())
     653             :   {
     654        3214 :     match_tree_list_list l;
     655             : 
     656        3214 :     match_tree_Re r;
     657        3214 :     match_tree_list readies;
     658             : 
     659        3214 :     pars.stack.push_front(match_tree_list_list());
     660        3214 :     l = pars.upstack;
     661        3214 :     pars.upstack = match_tree_list_list();
     662        3214 :     add_to_build_pars(pars,l,r,readies);
     663             : 
     664             : 
     665        3214 :     if (!r.is_defined())
     666             :     {
     667        2411 :       match_tree t = build_tree(pars,i);
     668             : 
     669        2411 :       for (; !readies.empty(); readies=readies.tail())
     670             :       {
     671           0 :         match_tree_CRe u(readies.front());
     672           0 :         inc_usedcnt(u.variables_condition());
     673           0 :         inc_usedcnt(u.variables_result());
     674           0 :         t = match_tree_C(u.condition(), match_tree_R(u.result()),t);
     675           0 :       }
     676             : 
     677        2411 :       return t;
     678        2411 :     }
     679             :     else
     680             :     {
     681         803 :       inc_usedcnt(r.variables());
     682         803 :       return match_tree_R(r.result());
     683             :     }
     684        3214 :   }
     685             :   else
     686             :   {
     687        7197 :     if (pars.stack.front().empty())
     688             :     {
     689        3612 :       if (pars.stack.tail().empty())
     690             :       {
     691        1776 :         return match_tree_X();
     692             :       }
     693             :       else
     694             :       {
     695        1836 :         pars.stack = pars.stack.tail();
     696        1836 :         return match_tree_D(build_tree(pars,i),0);
     697             :       }
     698             :     }
     699             :     else
     700             :     {
     701        3585 :       match_tree_list_list l = pars.stack.front();
     702        3585 :       match_tree_Re r ;
     703        3585 :       match_tree_list readies;
     704             : 
     705        3585 :       pars.stack = pars.stack.tail();
     706        3585 :       pars.stack.push_front(match_tree_list_list());
     707        3585 :       add_to_build_pars(pars,l,r,readies);
     708             : 
     709        3585 :       match_tree tree;
     710        3585 :       if (!r.is_defined())
     711             :       {
     712        3585 :         tree = build_tree(pars,i);
     713        3585 :         for (; !readies.empty(); readies=readies.tail())
     714             :         {
     715           0 :           match_tree_CRe t(readies.front());
     716           0 :           inc_usedcnt(t.variables_condition());
     717           0 :           inc_usedcnt(t.variables_result());
     718           0 :           tree = match_tree_C(t.condition(), match_tree_R(t.result()),tree);
     719           0 :         }
     720             :       }
     721             :       else
     722             :       {
     723           0 :         inc_usedcnt(r.variables());
     724           0 :         tree = match_tree_R(r.result());
     725             :       }
     726             : 
     727        3585 :       return match_tree_N(tree,0);
     728        3585 :     }
     729             :   }
     730             : }
     731             : 
     732        1080 : match_tree RewriterCompilingJitty::create_tree(const data_equation_list& rules)
     733             : // Create a match tree for OpId int2term[opid].
     734             : //
     735             : // Pre:  rules is a list of rewrite rules for some function symbol f.
     736             : // Ret:  A match tree for function symbol f.
     737             : {
     738             :   // Create sequences representing the trees for each rewrite rule and
     739             :   // store the total number of variables used in these sequences.
     740             :   // (The total number of variables in all sequences should be an upper
     741             :   // bound for the number of variable in the final tree.)
     742             : 
     743        1080 :   match_tree_list_list rule_seqs;
     744        1080 :   std::size_t total_rule_vars = 0;
     745        3748 :   for (const data_equation& e: rules)
     746             :   {
     747        2668 :     rule_seqs.push_front(create_sequence(e,&total_rule_vars));
     748             :   }
     749             :   // Generate initial parameters for built_tree
     750        1080 :   build_pars init_pars;
     751        1080 :   match_tree_Re r;
     752        1080 :   match_tree_list readies;
     753             : 
     754        1080 :   add_to_build_pars(init_pars,rule_seqs,r,readies);
     755        1080 :   match_tree tree;
     756        1080 :   if (!r.is_defined())
     757             :   {
     758        1080 :     treevars_usedcnt=std::vector < std::size_t> (total_rule_vars);
     759        1080 :     tree = build_tree(init_pars,0);
     760        1080 :     for (; !readies.empty(); readies=readies.tail())
     761             :     {
     762           0 :       match_tree_CRe u(readies.front());
     763           0 :       tree = match_tree_C(u.condition(), match_tree_R(u.result()), tree);
     764           0 :     }
     765             :   }
     766             :   else
     767             :   {
     768           0 :     tree = match_tree_R(r.result());
     769             :   }
     770        2160 :   return tree;
     771        1080 : }
     772             : 
     773             : // This function assigns a unique index to variable v and stores
     774             : // v at this position in the vector rewriter_bound_variables. This is
     775             : // used in the compiling rewriter to obtain this variable again.
     776             : // Note that the static variable variable_indices is not cleared
     777             : // during several runs, as generally the variables bound in rewrite
     778             : // rules do not change.
     779         156 : std::size_t RewriterCompilingJitty::bound_variable_index(const variable& v)
     780             : {
     781         156 :   if (variable_indices0.count(v)>0)
     782             :   {
     783         108 :     return variable_indices0[v];
     784             :   }
     785          48 :   const std::size_t index_for_v=rewriter_bound_variables.size();
     786          48 :   variable_indices0[v]=index_for_v;
     787          48 :   rewriter_bound_variables.push_back(v);
     788          48 :   return index_for_v;
     789             : }
     790             : 
     791             : // This function assigns a unique index to variable list vl and stores
     792             : // vl at this position in the vector rewriter_binding_variable_lists. This is
     793             : // used in the compiling rewriter to obtain this variable again.
     794             : // Note that the static variable variable_indices is not cleared
     795             : // during several runs, as generally the variables bound in rewrite
     796             : // rules do not change.
     797          44 : std::size_t RewriterCompilingJitty::binding_variable_list_index(const variable_list& vl)
     798             : {
     799          44 :   if (variable_list_indices1.count(vl)>0)
     800             :   {
     801           5 :     return variable_list_indices1[vl];
     802             :   }
     803          39 :   const std::size_t index_for_vl=rewriter_binding_variable_lists.size();
     804          39 :   variable_list_indices1[vl]=index_for_vl;
     805          39 :   rewriter_binding_variable_lists.push_back(vl);
     806          39 :   return index_for_vl;
     807             : }
     808             : 
     809             : // Put the sorts with indices between actual arity and requested arity in a vector.
     810         140 : sort_list_vector RewriterCompilingJitty::get_residual_sorts(const sort_expression& s1, std::size_t actual_arity, std::size_t requested_arity)
     811             : {
     812         140 :   sort_expression s=s1;
     813         140 :   sort_list_vector result;
     814         420 :   while (requested_arity>0)
     815             :   {
     816         280 :     const function_sort fs(s);
     817         280 :     if (actual_arity==0)
     818             :     {
     819         140 :       result.push_back(fs.domain());
     820         140 :       assert(fs.domain().size()<=requested_arity);
     821         140 :       requested_arity=requested_arity-fs.domain().size();
     822             :     }
     823             :     else
     824             :     {
     825         140 :       assert(fs.domain().size()<=actual_arity);
     826         140 :       actual_arity=actual_arity-fs.domain().size();
     827         140 :       requested_arity=requested_arity-fs.domain().size();
     828             :     }
     829         280 :     s=fs.codomain();
     830         280 :   }
     831         280 :   return result;
     832         140 : }
     833             : 
     834             : /// Rewrite the equation e such that it has exactly a arguments.
     835             : /// If the rewrite rule has too many arguments, false is returned, otherwise
     836             : /// additional arguments are added.
     837             : 
     838        2668 : bool RewriterCompilingJitty::lift_rewrite_rule_to_right_arity(data_equation& e, const std::size_t requested_arity)
     839             : {
     840        2668 :   data_expression lhs=e.lhs();
     841        2668 :   data_expression rhs=e.rhs();
     842        2668 :   variable_list vars=e.variables();
     843             : 
     844        2668 :   const data_expression& f=get_nested_head(lhs);
     845        2668 :   if (!is_function_symbol(f))
     846             :   {
     847           0 :     throw mcrl2::runtime_error("Equation " + pp(e) + " does not start with a function symbol in its left hand side.");
     848             :   }
     849             : 
     850        2668 :   std::size_t actual_arity=recursive_number_of_args(lhs);
     851        2668 :   if (arity_is_allowed(f.sort(),requested_arity) && actual_arity<=requested_arity)
     852             :   {
     853        2668 :     if (actual_arity<requested_arity)
     854             :     {
     855             :       // Supplement the lhs and rhs with requested_arity-actual_arity extra variables.
     856         140 :       sort_list_vector requested_sorts=get_residual_sorts(f.sort(),actual_arity,requested_arity);
     857         280 :       for(sort_list_vector::const_iterator sl=requested_sorts.begin(); sl!=requested_sorts.end(); ++sl)
     858             :       {
     859         140 :         variable_vector var_vec;
     860         382 :         for(sort_expression_list::const_iterator s=sl->begin(); s!=sl->end(); ++s)
     861             :         {
     862         242 :           variable v=variable(jitty_rewriter.identifier_generator()(),*s); // Find a new name for a variable that is temporarily in use.
     863         242 :           var_vec.push_back(v);
     864         242 :           vars.push_front(v);
     865         242 :         }
     866         140 :         lhs=application(lhs,var_vec.begin(),var_vec.end());
     867         140 :         rhs=application(rhs,var_vec.begin(),var_vec.end());
     868         140 :       }
     869         140 :     }
     870             :   }
     871             :   else
     872             :   {
     873           0 :     return false; // This is not an allowed arity, or the actual number of arguments is larger than the requested number.
     874             :   }
     875             : 
     876        2668 :   e=data_equation(vars,e.condition(),lhs,rhs);
     877        2668 :   return true;
     878        2668 : }
     879             : 
     880        1249 : match_tree_list RewriterCompilingJitty::create_strategy(const data_equation_list& rules, const std::size_t arity)
     881             : {
     882             :   typedef std::list<std::size_t> dep_list_t;
     883        1249 :   match_tree_list strat;
     884             :   // Maintain dependency count (i.e. the number of rules that depend on a given argument)
     885        1249 :   std::vector<std::size_t> arg_use_count(arity, 0);
     886        1249 :   std::list<std::pair<data_equation, dep_list_t> > rule_deps;
     887        4857 :   for (const data_equation& eq: rules)
     888             :   {
     889        3608 :     if (recursive_number_of_args(eq.lhs()) <= arity)
     890             :     {
     891        2668 :       rule_deps.push_front(std::make_pair(eq, dep_list_t()));
     892        2668 :       dep_list_t& deps = rule_deps.front().second;
     893             : 
     894        2668 :       const std::vector<bool> is_dependent_arg = dep_vars(eq);
     895        8035 :       for (std::size_t i = 0; i < is_dependent_arg.size(); i++)
     896             :       {
     897             :         // Only if needed and not already rewritten
     898        5367 :         if (is_dependent_arg[i])
     899             :         {
     900        4007 :           deps.push_back(i);
     901             :           // Increase dependency count
     902        4007 :           arg_use_count[i] += 1;
     903             :         }
     904             :       }
     905        2668 :     }
     906             :   }
     907             : 
     908             :   // Process all rules with their dependencies
     909        3322 :   while (!rule_deps.empty())
     910             :   {
     911        2073 :     data_equation_list no_deps;
     912        9026 :     for (std::list<std::pair<data_equation, dep_list_t> >::iterator it = rule_deps.begin(); it != rule_deps.end(); )
     913             :     {
     914        6953 :       if (it->second.empty())
     915             :       {
     916        2668 :         lift_rewrite_rule_to_right_arity(it->first, arity);
     917        2668 :         no_deps.push_front(it->first);
     918        2668 :         it = rule_deps.erase(it);
     919             :       }
     920             :       else
     921             :       {
     922        4285 :         ++it;
     923             :       }
     924             :     }
     925             : 
     926             :     // Create and add tree of collected rules
     927        2073 :     if (!no_deps.empty())
     928             :     {
     929        1080 :       strat.push_front(create_tree(no_deps));
     930             :     }
     931             : 
     932             :     // Figure out which argument is most useful to rewrite
     933        2073 :     std::size_t max = 0;
     934        2073 :     std::size_t maxidx = 0;
     935        6817 :     for (std::size_t i = 0; i < arity; i++)
     936             :     {
     937        4744 :       if (arg_use_count[i] > max)
     938             :       {
     939        1321 :         maxidx = i;
     940        1321 :         max = arg_use_count[i];
     941             :       }
     942             :     }
     943             : 
     944             :     // If there is a maximum, add it to the strategy and remove it from the dependency lists
     945        2073 :     assert(rule_deps.empty() || max > 0);
     946        2073 :     if (max > 0)
     947             :     {
     948        1288 :       assert(!rule_deps.empty());
     949        1288 :       arg_use_count[maxidx] = 0;
     950        1288 :       strat.push_front(match_tree_A(maxidx));
     951        5573 :       for (std::list<std::pair<data_equation, dep_list_t> >::iterator it = rule_deps.begin(); it != rule_deps.end(); ++it)
     952             :       {
     953        4285 :         it->second.remove(maxidx);
     954             :       }
     955             :     }
     956        2073 :   }
     957        2498 :   return reverse(strat);
     958        1249 : }
     959             : 
     960         459 : void RewriterCompilingJitty::extend_nfs(nfs_array& nfs, const function_symbol& opid, std::size_t arity)
     961             : {
     962         459 :   data_equation_list eqns = jittyc_eqns[opid];
     963         459 :   if (eqns.empty())
     964             :   {
     965         107 :     nfs.fill(true);
     966         107 :     return;
     967             :   }
     968         352 :   match_tree_list strat = create_strategy(eqns,arity);
     969         814 :   while (!strat.empty() && strat.front().isA())
     970             :   {
     971         462 :     nfs.at(match_tree_A(strat.front()).variable_index()) = true;
     972         462 :     strat = strat.tail();
     973             :   }
     974         459 : }
     975             : 
     976             : class rewr_function_spec
     977             : {
     978             :   protected:
     979             :     const function_symbol m_fs;
     980             :     const std::size_t m_arity;
     981             :     const bool m_delayed;
     982             : 
     983             :   public:
     984        3052 :     rewr_function_spec(function_symbol fs, std::size_t arity, const bool delayed)
     985        3052 :       : m_fs(fs), m_arity(arity), m_delayed(delayed)
     986        3052 :     { }
     987             : 
     988       30239 :     bool operator<(const rewr_function_spec& other) const
     989             :     {
     990       49967 :       return m_fs < other.m_fs ||
     991       67171 :              (m_fs == other.m_fs && m_arity < other.m_arity) ||
     992       57988 :              (m_fs == other.m_fs && m_arity == other.m_arity && m_delayed<other.m_delayed);
     993             :     }
     994             : 
     995        3259 :     function_symbol fs() const
     996             :     {
     997        3259 :       return m_fs;
     998             :     }
     999             : 
    1000        3733 :     std::size_t arity() const
    1001             :     {
    1002        3733 :       return m_arity;
    1003             :     }
    1004             : 
    1005        2050 :     bool delayed() const
    1006             :     {
    1007        2050 :       return m_delayed;
    1008             :     }
    1009             : 
    1010             :     bool operator==(const rewr_function_spec& other) const
    1011             :     {
    1012             :       return m_fs == other.m_fs && m_arity == other.m_arity && m_delayed==other.m_delayed;
    1013             :     }
    1014             : 
    1015        3966 :     std::string name() const
    1016             :     {
    1017        3966 :       std::stringstream name;
    1018        3966 :       if (m_delayed)
    1019             :       {
    1020         848 :         name << "delayed_";
    1021             :       }
    1022        3966 :       name << "rewr_" << atermpp::detail::index_traits<data::function_symbol,function_symbol_key_type, 2>::index(m_fs)
    1023        3966 :            << "_" << m_arity;
    1024        7932 :       return name.str();
    1025        3966 :     }
    1026             : };
    1027             : 
    1028             : class RewriterCompilingJitty::ImplementTree
    1029             : {
    1030             :   private:
    1031             :     class padding
    1032             :     {
    1033             :       private:
    1034             :         std::size_t m_indent;
    1035             :       public:
    1036           5 :         padding(std::size_t indent) : m_indent(indent) { }
    1037        4537 :         void indent() { m_indent += 2; }
    1038        4537 :         void unindent() { m_indent -= 2; }
    1039           0 :         std::size_t reset() { std::size_t old = m_indent; m_indent = 4; return old; }
    1040           0 :         void restore(const std::size_t i){ m_indent = i; }
    1041             :   
    1042             :         friend
    1043       33104 :         std::ostream& operator<<(std::ostream& stream, const padding& p)
    1044             :         {
    1045      228392 :           for (std::size_t i = p.m_indent; i != 0; --i)
    1046             :           {
    1047      195288 :             stream << ' ';
    1048             :           }
    1049       33104 :           return stream;
    1050             :         }
    1051             :     };
    1052             : 
    1053             :   RewriterCompilingJitty& m_rewriter;
    1054             :   std::stack<rewr_function_spec> m_rewr_functions;
    1055             :   std::set<rewr_function_spec> m_rewr_functions_implemented;
    1056             :   std::set<std::size_t>m_delayed_application_functions; // Recalls the arities of the required functions 'delayed_application';
    1057             :   std::vector<bool> m_used;
    1058             :   std::vector<int> m_stack;
    1059             :   padding m_padding;
    1060             :   // variable_or_number_list m_nnfvars;
    1061             : 
    1062             :   ///
    1063             :   /// \brief opid_is_nf establishes whether a function symbol is always in normal form.
    1064             :   ///        this is the case when there are no rewrite rules for the symbol.
    1065             :   /// \param opid The symbol to investigate.
    1066             :   /// \param num_args The arity of the function symbol.
    1067             :   /// \return true if the function symbol is always in normal form, false otherwise.
    1068             :   ///
    1069             :   bool opid_is_nf(const function_symbol& opid, std::size_t num_args)
    1070             :   {
    1071             :     data_equation_list l = m_rewriter.jittyc_eqns[opid];
    1072             :     for (data_equation_list::const_iterator it = l.begin(); it != l.end(); ++it)
    1073             :     {
    1074             :       if (recursive_number_of_args(it->lhs()) <= num_args)
    1075             :       {
    1076             :         return false;
    1077             :       }
    1078             :     }
    1079             :     return true;
    1080             :   }
    1081             : 
    1082             :   /// \brief appl_function returns the name of a function that can construct a data::application of
    1083             :   ///        arity `arity`.
    1084             :   /// \param arity the arity of the application that is to be constructed with the function.
    1085             :   /// \return the name of a function/constructor that creates an application (either of 'pass_on',
    1086             :   ///         'application' or 'make_term_with_many_arguments').
    1087             :   ///
    1088             :   static inline
    1089         661 :   const std::string appl_function(std::size_t arity)
    1090             :   {
    1091         661 :     if (arity == 0)
    1092             :     {
    1093           0 :       return "pass_on";  // This is to avoid confusion with atermpp::aterm_appl on a function symbol and two iterators.
    1094             :     }
    1095         661 :     return "make_application";
    1096             :   }
    1097             : 
    1098             :   inline
    1099        2204 :   const std::string rewr_function_name(const function_symbol& f, std::size_t arity)
    1100             :   {
    1101        2204 :     rewr_function_spec spec(f, arity, false);
    1102        2204 :     if (m_rewr_functions_implemented.insert(spec).second)
    1103             :     {
    1104         897 :       m_rewr_functions.push(spec);
    1105             :     }
    1106        4408 :     return spec.name();
    1107        2204 :   }
    1108             : 
    1109             :   inline
    1110         848 :   const std::string delayed_rewr_function_name(const function_symbol& f, std::size_t arity)
    1111             :   {
    1112         848 :     rewr_function_spec spec(f, arity, true);
    1113         848 :     if (m_rewr_functions_implemented.insert(spec).second)
    1114             :     {
    1115         128 :       m_rewr_functions.push(spec);
    1116             :     }
    1117         848 :     rewr_function_name(f,arity); // Also declare the non delayed function.
    1118        1696 :     return spec.name();
    1119         848 :   }
    1120             : 
    1121             :   /*
    1122             :    * calc_inner_term helper methods
    1123             :    *
    1124             :    */
    1125             : 
    1126        1955 :   void calc_inner_term_variable(std::ostream& s, 
    1127             :                                 const std::string& target_for_output,
    1128             :                                 const variable& v, 
    1129             :                                 const bool require_normal_form,
    1130             :                                 std::ostream& result_type,
    1131             :                                 const std::map<variable,std::string>& type_of_code_variables) 
    1132             :   {
    1133        1955 :     const std::string variable_name = v.name();
    1134             :     // Remove the initial @ if it is present in the variable name, because then it is a variable introduced
    1135             :     // by this rewriter.
    1136        1955 :     if (variable_name[0] == '@')
    1137             :     {
    1138        1799 :       assert(type_of_code_variables.count(v)>0);  // We know the type of the variable at hand. 
    1139        1799 :       if (require_normal_form)
    1140             :       {
    1141         765 :         if (type_of_code_variables.at(v)=="data_expression")
    1142             :         {
    1143         185 :           if (target_for_output.empty())
    1144             :           {
    1145          82 :             s << variable_name.substr(1);
    1146             :           }
    1147             :           else 
    1148             :           {
    1149         206 :             s << m_padding << target_for_output << ".assign(" << variable_name.substr(1) 
    1150         103 :                            << ", *this_rewriter->m_thread_aterm_pool);\n";
    1151             :           }
    1152             :         }
    1153             :         else 
    1154             :         {
    1155         580 :           if (target_for_output.empty())
    1156             :           {
    1157         412 :             s << "local_rewrite(" << variable_name.substr(1) << ")";
    1158             :           }
    1159             :           else
    1160             :           {
    1161         168 :             s << m_padding << "local_rewrite(" << target_for_output << ", " << variable_name.substr(1) << ");\n";
    1162             :           }
    1163             :         }
    1164         765 :         result_type << "data_expression";
    1165             :       }
    1166             :       else // No normal form is required. 
    1167             :       {
    1168        1034 :         assert(target_for_output.empty());
    1169        1034 :         s << variable_name.substr(1);
    1170        1034 :         if (type_of_code_variables.at(v)=="data_expression")
    1171             :         {
    1172         771 :           result_type << "data_expression";
    1173             :         }
    1174             :         else 
    1175             :         {
    1176         263 :           assert(variable_name.substr(0,5)=="@var_");
    1177         263 :           result_type << type_of_code_variables.at(v);
    1178             :         }
    1179             :       }
    1180        1799 :       return;
    1181             :     }
    1182             :     else
    1183             :     {
    1184         156 :       if (target_for_output.empty())
    1185             :       {
    1186         156 :         s << "static_cast<const data_expression&>(this_rewriter->bound_variable_get(" << m_rewriter.bound_variable_index(v) << "))";
    1187             :       }
    1188             :       else
    1189             :       {
    1190             :         // s << m_padding << target_for_output << " = " << 
    1191             :         //     "static_cast<const data_expression&>(this_rewriter->bound_variable_get(" << m_rewriter.bound_variable_index(v) << "))\n";
    1192           0 :         s << m_padding << target_for_output << ".assign(" 
    1193           0 :           << "static_cast<const data_expression&>(this_rewriter->bound_variable_get(" << m_rewriter.bound_variable_index(v) << ")), " 
    1194           0 :           << "this_rewriter), *this_rewriter->m_thread_aterm_pool);\n";
    1195             :       }
    1196         156 :       result_type << "data_expression";
    1197         156 :       return;
    1198             :     }
    1199        1955 :   }
    1200             : 
    1201          44 :   void calc_inner_term_abstraction(
    1202             :                     std::ostream& s, 
    1203             :                     const std::string& target_for_output,
    1204             :                     const abstraction& a, 
    1205             :                     const std::size_t startarg, 
    1206             :                     const bool require_normal_form, 
    1207             :                     std::ostream& result_type, 
    1208             :                     const std::map<variable,std::string>& type_of_code_variables)
    1209             :   {
    1210          44 :     std::string binder_constructor;
    1211          44 :     std::string rewriter_function;
    1212          44 :     if (is_lambda_binder(a.binding_operator()))
    1213             :     {
    1214           0 :       binder_constructor = "lambda_binder";
    1215           0 :       rewriter_function = "rewrite_single_lambda";
    1216             :     }
    1217             :     else
    1218          44 :     if (is_forall_binder(a.binding_operator()))
    1219             :     {
    1220          44 :       binder_constructor = "forall_binder";
    1221          44 :       rewriter_function = "universal_quantifier_enumeration";
    1222             :     }
    1223             :     else
    1224             :     {
    1225           0 :       assert(is_exists_binder(a.binding_operator()));
    1226           0 :       binder_constructor = "exists_binder";
    1227           0 :       rewriter_function = "existential_quantifier_enumeration";
    1228             :     }
    1229          44 :     if (require_normal_form)
    1230             :     {
    1231          44 :       if (target_for_output.empty())
    1232             :       {
    1233           0 :         std::stringstream argument;
    1234           0 :         calc_inner_term(argument, "", a.body(), startarg, true, result_type, type_of_code_variables);
    1235             :         s << "this_rewriter->" << rewriter_function << "(" << 
    1236           0 :              "this_rewriter->binding_variable_list_get(" << m_rewriter.binding_variable_list_index(a.variables()) << "), ";
    1237           0 :         s << argument.str() << ", true, sigma(this_rewriter))";
    1238           0 :         result_type << "data_expression";
    1239           0 :         return;
    1240           0 :       }
    1241             :       else
    1242             :       {
    1243          44 :         calc_inner_term(s, target_for_output, a.body(), startarg, true, result_type, type_of_code_variables);
    1244          44 :         s << m_padding << "this_rewriter->" << rewriter_function << "(" << target_for_output << 
    1245          44 :              ", this_rewriter->binding_variable_list_get(" << m_rewriter.binding_variable_list_index(a.variables()) << "), ";
    1246          44 :         s << target_for_output << ", true, sigma(this_rewriter));\n";
    1247          44 :         result_type << "data_expression";
    1248          44 :         return;
    1249             :       }
    1250             :     }
    1251             :     else
    1252             :     {
    1253           0 :       std::stringstream argument_type;
    1254           0 :       std::stringstream argument_string;
    1255           0 :       calc_inner_term(argument_string, "", a.body(), startarg, false, argument_type, type_of_code_variables);
    1256           0 :       s << "delayed_abstraction<" << argument_type.str() << ">(" << binder_constructor << "(), "
    1257           0 :            "this_rewriter->binding_variable_list_get(" << m_rewriter.binding_variable_list_index(a.variables()) << "), ";
    1258           0 :       s << argument_string.str() << ", this_rewriter)";
    1259           0 :       result_type << "delayed_abstraction<" << argument_type.str() << ">";
    1260           0 :       return;
    1261           0 :     }
    1262          44 :   }
    1263             : 
    1264           0 :   void calc_inner_term_where_clause(std::ostream& s, 
    1265             :                                     const std::string& target_for_output,
    1266             :                                     const where_clause& w, 
    1267             :                                     const std::size_t startarg, 
    1268             :                                     const bool require_normal_form, 
    1269             :                                     std::ostream& result_type, 
    1270             :                                     const std::map<variable,std::string>& type_of_code_variables)
    1271             :   {
    1272           0 :     if (require_normal_form)  // TODO Take into account that some arguments are already in normal form.
    1273             :     {
    1274           0 :       if (target_for_output.empty())
    1275             :       {
    1276           0 :         s << "this_rewriter->rewrite_where(";
    1277             :       }
    1278             :       else
    1279             :       {
    1280           0 :         s << m_padding << "this_rewriter->rewrite_where(" << target_for_output << ", ";
    1281             :       }
    1282           0 :       result_type << "data_expression";
    1283             :     }
    1284             :     else
    1285             :     {
    1286           0 :       s << "term_not_in_normal_form(";
    1287           0 :       result_type << "term_not_in_normal_form";
    1288             :     }
    1289             :     // A rewritten result is expected.
    1290           0 :     std::stringstream temp_result_type;
    1291           0 :     s << "where_clause(";
    1292           0 :     calc_inner_term(s, "", w.body(), startarg, true, temp_result_type, type_of_code_variables);
    1293           0 :     s << ",";
    1294           0 :     for(std::size_t i = w.assignments().size(); i > 0; --i)
    1295             :     {
    1296           0 :       s << "jittyc_local_push_front(";
    1297             :     }
    1298           0 :     s << "assignment_expression_list()";
    1299           0 :     for(assignment_list::const_iterator i = w.assignments().begin(); i != w.assignments().end(); ++i)
    1300             :     {
    1301           0 :       s << ", assignment(this_rewriter->bound_variable_get(" << m_rewriter.bound_variable_index(i->lhs()) << "), ";
    1302           0 :       calc_inner_term(s, "", i->rhs(), startarg, true, temp_result_type, type_of_code_variables);
    1303           0 :       s << "))";
    1304             :     }
    1305           0 :     s << ")";
    1306           0 :     if (require_normal_form)
    1307             :     {
    1308           0 :       s << ", sigma(this_rewriter))";
    1309             :     }
    1310             :     else
    1311             :     {
    1312           0 :       s << ", this_rewriter)";
    1313             :     }
    1314           0 :     if (!target_for_output.empty())
    1315             :     {
    1316           0 :       s << ";\n";
    1317             :     }
    1318           0 :   }
    1319             : 
    1320         883 :   bool calc_inner_term_appl_function(std::ostream& s,
    1321             :                                      const std::string& target_for_output,
    1322             :                                      const application& a,
    1323             :                                      const function_symbol& head,
    1324             :                                      const std::size_t startarg,
    1325             :                                      const bool require_normal_form,
    1326             :                                      std::ostream& result_type,
    1327             :                                      const std::map<variable,std::string>& type_of_code_variables)
    1328             :   {
    1329         883 :     const std::size_t arity = recursive_number_of_args(a);
    1330             : 
    1331         883 :     assert(arity > 0);
    1332         883 :     nfs_array args_nfs(arity);
    1333         883 :     if (require_normal_form)
    1334             :     {
    1335             :       // Take care that arguments that need to be rewritten,
    1336             :       // are rewritten immediately.
    1337         459 :       m_rewriter.extend_nfs(args_nfs, head, arity);
    1338             :     }
    1339             : 
    1340             :     // First calculate the code to be generated for the arguments.
    1341             :     // This provides the information which arguments are certainly in normal
    1342             :     // form, which can be used to optimise the result.
    1343             : 
    1344         883 :     std::stringstream code_for_arguments;
    1345         883 :     std::stringstream types_for_arguments;
    1346         883 :     args_nfs.fill(false);
    1347         883 :     calc_inner_terms(code_for_arguments, a, startarg, args_nfs, types_for_arguments, type_of_code_variables);
    1348             : 
    1349         883 :     if (require_normal_form)
    1350             :     {
    1351         459 :       if (target_for_output.empty())
    1352             :       {
    1353           0 :         result_type << "data_expression";
    1354           0 :         s << delayed_rewr_function_name(head, arity) << "(";
    1355             :       }
    1356             :       else
    1357             :       {
    1358         459 :         result_type << "data_expression";
    1359         459 :         s << m_padding << rewr_function_name(head, arity) << "(" << target_for_output << ", ";
    1360             :       }
    1361             :     }
    1362             :     else
    1363             :     {
    1364         424 :       s << delayed_rewr_function_name(head, arity);
    1365         424 :       result_type << delayed_rewr_function_name(head, arity);
    1366         424 :       if (arity>0)
    1367             :       {
    1368         424 :         s << "<" << types_for_arguments.str() << ">";
    1369         424 :         result_type << "<" << types_for_arguments.str() << ">";
    1370             :       }
    1371         424 :       s << "(";
    1372             :     }
    1373         883 :     s << code_for_arguments.str();
    1374         883 :     s <<  (code_for_arguments.str().empty()?"":", ") << "this_rewriter)";
    1375             : 
    1376         883 :     if (require_normal_form)
    1377             :     {
    1378         459 :       if (target_for_output.empty())
    1379             :       {
    1380           0 :         s << ".normal_form()";
    1381             :       }
    1382             :       else
    1383             :       {
    1384         459 :         s << ";\n";
    1385             :       }
    1386             :     }
    1387             : 
    1388         883 :     return require_normal_form;
    1389         883 :   }
    1390             : 
    1391           0 :   bool calc_inner_term_appl_lambda_abstraction(
    1392             :                             std::ostream& s,
    1393             :                             const std::string& target_for_output,
    1394             :                             const application& a,
    1395             :                             const abstraction& head,
    1396             :                             const std::size_t startarg,
    1397             :                             const bool require_normal_form,
    1398             :                             std::ostream& result_type,
    1399             :                             const std::map<variable,std::string>& type_of_code_variables)
    1400             :   {
    1401           0 :     assert(a.size() > 0);    // TODO Take care that the application of this lambda is done without unnecessary rewriting.
    1402             :                              // The problem is that the function rewrite_lambda_application rewrites all its arguments.
    1403             :                              // This should be lifted to a templated function. Furthermore, in the not rewritten variant,
    1404             :                              // all arguments are also rewritten to normal form, to guarantee that they are of sort dataexpression.
    1405           0 :     assert(is_lambda_binder(head.binding_operator()));
    1406           0 :     const std::size_t arity = a.size();
    1407             : 
    1408           0 :     if (require_normal_form)
    1409             :     {
    1410           0 :       nfs_array args_nfs(recursive_number_of_args(a));
    1411           0 :       args_nfs.fill(true);
    1412             : 
    1413           0 :       s << m_padding << appl_function(arity) << "(" + target_for_output + ",";
    1414           0 :       std::stringstream types_for_arguments;
    1415           0 :       calc_inner_term(s, "", head, startarg, true, types_for_arguments, type_of_code_variables);
    1416           0 :       s << ", ";
    1417           0 :       if (arity>0)
    1418             :       {
    1419           0 :         types_for_arguments << ", ";
    1420             :       }
    1421           0 :       calc_inner_terms(s, a, startarg, args_nfs,types_for_arguments, type_of_code_variables);
    1422           0 :       s << ");\n";
    1423           0 :       s << m_padding << "this_rewriter->rewrite_lambda_application(" << target_for_output << ", " << target_for_output;
    1424           0 :       result_type << "data_expression";
    1425             : 
    1426           0 :       s << ", sigma(this_rewriter));\n";
    1427           0 :       return require_normal_form;
    1428           0 :     }
    1429             :     else
    1430             :     {
    1431             :       // !require_normal_form
    1432           0 :       nfs_array args_nfs(arity);
    1433           0 :       args_nfs.fill(true);
    1434             : 
    1435           0 :       s << m_padding << appl_function(arity) << "(" << target_for_output;
    1436           0 :       std::stringstream types_for_arguments;
    1437           0 :       calc_inner_term(s, target_for_output, head, startarg, true, types_for_arguments, type_of_code_variables);
    1438           0 :       s << ", ";
    1439           0 :       if (arity>0)
    1440             :       {
    1441           0 :         types_for_arguments << ", ";
    1442             :       }
    1443           0 :       calc_inner_terms(s, a, startarg, args_nfs,types_for_arguments, type_of_code_variables);
    1444           0 :       s << ");\n";
    1445           0 :       s << m_padding << target_for_output << "= term_not_in_normalform(" << target_for_output << ");\n";
    1446           0 :       result_type << "term_not_in_normalform";
    1447           0 :       return require_normal_form;
    1448           0 :     }
    1449             :   }
    1450             : 
    1451         136 :   void write_application_to_stream_in_normal_form(
    1452             :                             std::ostream& s,
    1453             :                             const std::string& target_for_output,
    1454             :                             const application& a,
    1455             :                             const std::size_t startarg,
    1456             :                             const std::map<variable,std::string>& type_of_code_variables)
    1457             :   { 
    1458             :     // the application is either application(variable,t1,..,tn) or application(application(...),t1,..,tn).
    1459             : 
    1460         136 :     const std::size_t arity = a.size();
    1461         136 :     nfs_array rewr_args(arity);
    1462         136 :     rewr_args.fill(true);
    1463         136 :     std::stringstream dummy_result_type;  // As we rewrite to normal forms, these are always data_expressions.
    1464             : 
    1465         136 :     if (target_for_output.empty())
    1466             :     {
    1467           0 :       if (is_variable(a.head()))
    1468             :       {
    1469           0 :         s << "application(";
    1470           0 :         calc_inner_term(s, "", down_cast<variable>(a.head()), startarg, true, dummy_result_type, type_of_code_variables);
    1471             :       }
    1472             :       else
    1473             :       {
    1474           0 :         assert(is_application(a.head()));
    1475           0 :         s << "application(";
    1476           0 :         write_application_to_stream_in_normal_form(s,"",down_cast<application>(a.head()),startarg, type_of_code_variables);
    1477             :       }
    1478           0 :       for(const data_expression& t: a)
    1479             :       {
    1480           0 :         s << ", ";
    1481             : 
    1482           0 :         calc_inner_term(s, "", t, startarg, rewr_args, dummy_result_type, type_of_code_variables);
    1483             :       }
    1484           0 :       s << ")";
    1485             :     }
    1486             :     else 
    1487             :     {
    1488         136 :       if (is_variable(a.head()))
    1489             :       {
    1490         136 :         s << m_padding << appl_function(arity) << "(" << target_for_output << ",";
    1491         136 :         calc_inner_term(s, "", down_cast<variable>(a.head()), startarg, true, dummy_result_type, type_of_code_variables);
    1492             :       }
    1493             :       else
    1494             :       {
    1495           0 :         assert(is_application(a.head()));
    1496           0 :         write_application_to_stream_in_normal_form(s,target_for_output,down_cast<application>(a.head()),startarg, type_of_code_variables);
    1497           0 :         s << m_padding << appl_function(arity) << "(" << target_for_output << "," << target_for_output;
    1498           0 :         std::stringstream dummy_result_type;  // As we rewrite to normal forms, these are always data_expressions.
    1499           0 :       }
    1500         374 :       for(const data_expression& t: a)
    1501             :       {
    1502         238 :         s << ", ";
    1503             : 
    1504         238 :         calc_inner_term(s, "", t, startarg, rewr_args, dummy_result_type, type_of_code_variables);
    1505             :       }
    1506         136 :       s << ");\n";
    1507             :     }
    1508         136 :   }
    1509             : 
    1510         104 :   std::string delayed_application(const std::size_t arity)
    1511             :   {
    1512         104 :     m_delayed_application_functions.insert(arity);
    1513         104 :     std::stringstream s;
    1514         104 :     s << "delayed_application" << arity;
    1515         208 :     return s.str();
    1516         104 :   }
    1517             : 
    1518         104 :   void write_delayed_application_to_stream_in_normal_form(
    1519             :                             std::ostream& s,
    1520             :                             const application& a,
    1521             :                             const std::size_t startarg,
    1522             :                             std::ostream& result_type,
    1523             :                             const std::map<variable,std::string>& type_of_code_variables)
    1524             :   {
    1525             :     // the application is either application(variable,t1,..,tn) or application(application(...),t1,..,tn).
    1526             : 
    1527         104 :     const std::size_t arity = a.size();
    1528         104 :     nfs_array rewr_args(arity);
    1529         104 :     rewr_args.fill(true);
    1530         104 :     std::stringstream code_string;
    1531         104 :     std::stringstream result_types;
    1532             : 
    1533         104 :     if (is_variable(a.head()))
    1534             :     {
    1535         104 :       calc_inner_term(code_string, "", down_cast<variable>(a.head()), startarg, true, result_types, type_of_code_variables);
    1536             :     }
    1537             :     else
    1538             :     {
    1539           0 :       assert(is_application(a.head()));
    1540           0 :       write_delayed_application_to_stream_in_normal_form(code_string,down_cast<application>(a.head()),startarg, result_types, type_of_code_variables);
    1541             :     }
    1542             : 
    1543         276 :     for(const data_expression& t: a)
    1544             :     {
    1545         172 :       result_types << ",";
    1546         172 :       code_string << ", ";
    1547         172 :       calc_inner_term(code_string, "", t, startarg, true, result_types, type_of_code_variables);
    1548             :     }
    1549             : 
    1550         104 :     s << delayed_application(arity) << "<" << result_types.str() << ">(";
    1551         104 :     s << code_string.str();
    1552         104 :     s << ", this_rewriter)";
    1553             : 
    1554         104 :     result_type << "delayed_application" << arity << "<" << result_types.str() << ">";
    1555         104 :   }
    1556             : 
    1557         240 :   bool calc_inner_term_appl_variable
    1558             :                            (std::ostream& s,
    1559             :                             const std::string& target_for_output,
    1560             :                             const application& a,
    1561             :                             const std::size_t startarg,
    1562             :                             const bool require_normal_form,
    1563             :                             std::ostream& result_type,
    1564             :                             const std::map<variable,std::string>& type_of_code_variables)
    1565             :   {
    1566         240 :     if (require_normal_form)
    1567             :     {
    1568         136 :       result_type << "data_expression";
    1569         136 :       if (target_for_output.empty())
    1570             :       {
    1571           0 :         s << "rewrite_with_arguments_in_normal_form(";
    1572           0 :         write_application_to_stream_in_normal_form(s,"",a,startarg, type_of_code_variables);
    1573           0 :         s << ", this_rewriter)";
    1574             :       }
    1575             :       else
    1576             :       {
    1577         136 :         write_application_to_stream_in_normal_form(s,target_for_output,a,startarg, type_of_code_variables);
    1578         136 :         s << m_padding << "rewrite_with_arguments_in_normal_form(" << target_for_output << ", "
    1579         136 :           << target_for_output << ", this_rewriter);\n";
    1580             :       }
    1581         136 :       return true;
    1582             :     }
    1583             : 
    1584             :     // Generate an application which is rewritten when it is needed.
    1585         104 :     write_delayed_application_to_stream_in_normal_form(s,a,startarg, result_type, type_of_code_variables);
    1586         104 :     return false;
    1587             :   }
    1588             : 
    1589        1123 :   bool calc_inner_term_application(std::ostream& s,
    1590             :                                    const std::string& target_for_output,
    1591             :                                    const application& a,
    1592             :                                    const std::size_t startarg,
    1593             :                                    const bool require_normal_form,
    1594             :                                    std::ostream& result_type,
    1595             :                                    const std::map<variable,std::string>& type_of_code_variables)
    1596             :   {
    1597        1123 :     const data_expression head=get_nested_head(a);
    1598             : 
    1599        1123 :     if (is_function_symbol(head))  // Determine whether the topmost symbol is a function symbol.
    1600             :     {
    1601         883 :       return calc_inner_term_appl_function(s, target_for_output, a, down_cast<function_symbol>(head), startarg, require_normal_form, result_type, type_of_code_variables);
    1602             :     }
    1603             : 
    1604         240 :     if (is_abstraction(head)) // Here we must consider the case where head is an abstraction, and hence it must be a lambda abstraction.
    1605             :     {
    1606           0 :       return calc_inner_term_appl_lambda_abstraction(s, target_for_output, a, down_cast<abstraction>(head), startarg, require_normal_form, result_type, type_of_code_variables);
    1607             :     }
    1608             : 
    1609         240 :     assert(is_variable(head)); // Here we must consider the case where head is a variable.
    1610         240 :     return calc_inner_term_appl_variable(s, target_for_output, a, startarg, require_normal_form, result_type, type_of_code_variables);
    1611        1123 :   }
    1612             : 
    1613             :   ///
    1614             :   /// \brief calc_inner_term generates C++ code that reconstructs data expression t.
    1615             :   /// \param s is the stream to write the generated code to.
    1616             :   /// \param target_for_output is a reference expression to which the output must be assigned, or in case of the empty string,
    1617             :   //         it is the result of the expression. 
    1618             :   /// \param t is the data expression to be reconstructed in the generated code.
    1619             :   /// \param startarg gives the index of the position of t in the surrounding application (0 for head position, 1 for first argument, etc.)
    1620             :   /// \param require_normal_form indicates whether the reconstructed data expression should be rewritten to normal form.
    1621             :   /// \param type_of_code_variables gives the type of the variables used in the generated C++ code. data_expression means is in normal form.
    1622             :   /// \return True if the result is in normal form, false otherwise.
    1623             :   ///
    1624        3608 :   void calc_inner_term(std::ostream& s,
    1625             :                        const std::string& target_for_output,
    1626             :                        const data_expression& t,
    1627             :                        const std::size_t startarg,
    1628             :                        const bool require_normal_form,
    1629             :                        std::ostream& result_type,
    1630             :                        const std::map<variable,std::string>& type_of_code_variables)
    1631             :   {
    1632        3608 :     if (find_free_variables(t).empty())
    1633             :     {
    1634         486 :       if (target_for_output.empty())
    1635             :       { 
    1636          43 :         RewriterCompilingJitty::substitution_type sigma;
    1637          43 :         s << m_rewriter.m_nf_cache->insert(m_rewriter.jitty_rewriter(t,sigma));
    1638          43 :       }
    1639             :       else
    1640             :       {
    1641         443 :         RewriterCompilingJitty::substitution_type sigma;
    1642         443 :         s << m_padding << target_for_output 
    1643             :           << ".unprotected_assign<false>("
    1644         886 :           << m_rewriter.m_nf_cache->insert(m_rewriter.jitty_rewriter(t,sigma)) 
    1645         886 :           << ");\n";
    1646         443 :       }
    1647         486 :       result_type << "data_expression";
    1648         486 :       return;
    1649             :     }
    1650        3122 :     assert(!is_function_symbol(t)); // This will never be reached, as it is dealt with in the if clause above.
    1651             :     
    1652        3122 :     if (is_variable(t))
    1653             :     {
    1654        1955 :       calc_inner_term_variable(s, target_for_output, down_cast<variable>(t), require_normal_form, result_type, type_of_code_variables);
    1655        1955 :       return;
    1656             :     }
    1657        1167 :     if (is_abstraction(t))
    1658             :     {
    1659          44 :       calc_inner_term_abstraction(s, target_for_output, down_cast<abstraction>(t), startarg, require_normal_form, result_type, type_of_code_variables);
    1660          44 :       return;
    1661             :     }
    1662        1123 :     if (is_where_clause(t))
    1663             :     {
    1664           0 :       calc_inner_term_where_clause(s, target_for_output, down_cast<where_clause>(t), startarg, require_normal_form, result_type, type_of_code_variables);
    1665           0 :       return;
    1666             :     }
    1667             : 
    1668        1123 :     assert(is_application(t));
    1669        1123 :     calc_inner_term_application(s, target_for_output, down_cast<application>(t), startarg, require_normal_form, result_type, type_of_code_variables);
    1670             :   }
    1671             : 
    1672             :   ///
    1673             :   /// \brief calc_inner_terms calls calc_inner_term on all arguments of t, passing the corresponding
    1674             :   ///        bools in the rewr array as the rewr parameter. Returns the booleans returned by those
    1675             :   ///        calls as a vector.
    1676             :   ///
    1677         883 :   void calc_inner_terms(std::ostream& s,
    1678             :                         const application& appl,
    1679             :                         const std::size_t startarg,
    1680             :                         const nfs_array& rewr,   /// A Boolean would be enough. TODO:
    1681             :                         std::ostream& argument_types,
    1682             :                         const std::map<variable,std::string>& type_of_code_variables)
    1683             :   {
    1684        2488 :     for(std::size_t i=0; i<recursive_number_of_args(appl); ++i)
    1685             :     {
    1686        1605 :       if (i > 0)
    1687             :       {
    1688         722 :         s << ", ";
    1689         722 :         argument_types << ", ";
    1690             :       }
    1691        1605 :       std::stringstream argument_string;
    1692        1605 :       std::stringstream argument_type;
    1693        1605 :       assert(i<rewr.size());
    1694        1605 :       calc_inner_term(argument_string, "", get_argument_of_higher_order_term(appl,i), startarg + i, rewr.at(i), 
    1695             :                       argument_type, type_of_code_variables);
    1696        1605 :       s << argument_string.str();
    1697        1605 :       argument_types << argument_type.str();
    1698        1605 :     }
    1699         883 :   }
    1700             : 
    1701             :   /*
    1702             :    * implement_tree helper methods.
    1703             :    * type_of_code_variables gives a mapping from the variables used in the generated code. 
    1704             :    * if it is "data_expression" then it is a normal form. Otherwise it is a template type, which
    1705             :    * may or may not be a normal form. 
    1706             :    *
    1707             :    */
    1708             : 
    1709        7028 :   void implement_tree(std::ostream& m_stream,
    1710             :                       const match_tree& tree, 
    1711             :                       std::size_t cur_arg, 
    1712             :                       std::size_t parent, 
    1713             :                       std::size_t level, 
    1714             :                       std::size_t cnt,
    1715             :                       const std::size_t arity,
    1716             :                       const function_symbol& opid,
    1717             :                       bracket_level_data& brackets, 
    1718             :                       std::stack<std::string>& auxiliary_code_fragments,
    1719             :                       std::map<variable,std::string>& type_of_code_variables)
    1720             :   {
    1721             :     /* Some c++ compilers cannot deal with more than 256 nestings of curly braces ({...}). 
    1722             :        If too many curly braces are generated, a new method is generated, with as only  purpose
    1723             :        to avoid too many brackets. The resulting code fragments are stored in auxiliary_code_fragments.
    1724             :     */
    1725        7028 :     if (brackets.bracket_nesting_level>brackets.MCRL2_BRACKET_NESTING_LEVEL)
    1726             :     {
    1727             :       static std::size_t auxiliary_method_name_index=0;
    1728             : 
    1729           0 :       m_stream << m_padding 
    1730           0 :                << "auxiliary_function_to_reduce_bracket_nesting" << auxiliary_method_name_index << "(result, "
    1731           0 :                << brackets.current_data_arguments.top() << ",this_rewriter);\n";
    1732           0 :       m_stream << m_padding 
    1733           0 :                << "if (!result.is_default_data_expression()) { return; }\n";
    1734             : 
    1735           0 :       const std::size_t old_indent=m_padding.reset();
    1736           0 :       std::stringstream s;
    1737           0 :       s << "  template < " << brackets.current_template_parameters << ">\n"
    1738           0 :         << "  static inline void auxiliary_function_to_reduce_bracket_nesting" << auxiliary_method_name_index 
    1739             :         << "(data_expression& result" 
    1740           0 :         << brackets.current_data_parameters.top() << (brackets.current_data_parameters.top().empty()?"":", ") << "RewriterCompilingJitty* this_rewriter)\n" 
    1741             :         << "  {\n"
    1742           0 :         << "    std::size_t old_stack_size=this_rewriter->m_rewrite_stack.stack_size();\n";
    1743             :       
    1744           0 :       auxiliary_method_name_index++;
    1745             : 
    1746           0 :       std::size_t old_bracket_nesting_level=brackets.bracket_nesting_level;
    1747           0 :       brackets.bracket_nesting_level=0;
    1748           0 :       implement_tree(s,tree,cur_arg,parent,level,cnt,arity, opid, brackets,auxiliary_code_fragments, type_of_code_variables);
    1749           0 :       brackets.bracket_nesting_level=old_bracket_nesting_level;
    1750             :       s << "    make_data_expression(result); return; // This indicates that no result has been calculated;\n"
    1751             :         << "  }\n"
    1752           0 :         << "\n";
    1753           0 :       m_padding.restore(old_indent);
    1754           0 :       auxiliary_code_fragments.push(s.str());  
    1755           0 :       return;
    1756           0 :     }
    1757             : 
    1758        7028 :     if (tree.isS())
    1759             :     {
    1760        1527 :       implement_treeS(m_stream,atermpp::down_cast<match_tree_S>(tree), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1761             :     }
    1762        5501 :     else if (tree.isM())
    1763             :     {
    1764         368 :       implement_treeM(m_stream,atermpp::down_cast<match_tree_M>(tree), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1765             :     }
    1766        5133 :     else if (tree.isF())
    1767             :     {
    1768         852 :       implement_treeF(m_stream, atermpp::down_cast<match_tree_F>(tree), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1769             :     }
    1770        4281 :     else if (tree.isD())
    1771             :     {
    1772         584 :       implement_treeD(m_stream, atermpp::down_cast<match_tree_D>(tree), level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1773             :     }
    1774        3697 :     else if (tree.isN())
    1775             :     {
    1776        1721 :       implement_treeN(m_stream, atermpp::down_cast<match_tree_N>(tree), cur_arg, parent, level, cnt, arity, opid, brackets,auxiliary_code_fragments, type_of_code_variables);
    1777             :     }
    1778        1976 :     else if (tree.isC())
    1779             :     {
    1780          58 :       implement_treeC(m_stream, atermpp::down_cast<match_tree_C>(tree), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1781             :     }
    1782        1918 :     else if (tree.isR())
    1783             :     {
    1784        1251 :       implement_treeR(m_stream, atermpp::down_cast<match_tree_R>(tree), cur_arg, level, type_of_code_variables);
    1785             :     }
    1786             :     else
    1787             :     {
    1788             :       // These are the only remaining case, where we do not have to do anything.
    1789         667 :       assert(tree.isA() || tree.isX() || tree.isMe());
    1790             :     }
    1791             :   }
    1792             : 
    1793             :   class matches
    1794             :   {
    1795             :     protected:
    1796             :      const aterm m_matchterm;
    1797             : 
    1798             :     public:
    1799        1527 :       matches(const aterm& matchterm)
    1800        1527 :        : m_matchterm(matchterm)
    1801        1527 :       {}
    1802             : 
    1803       39845 :       bool operator ()(const atermpp::aterm& t) const
    1804             :       {
    1805       39845 :         return t==m_matchterm;
    1806             :       }
    1807             :   };
    1808             : 
    1809        1527 :   void implement_treeS(
    1810             :              std::ostream& m_stream,
    1811             :              const match_tree_S& tree, 
    1812             :              std::size_t cur_arg, 
    1813             :              std::size_t parent, 
    1814             :              std::size_t level, 
    1815             :              std::size_t cnt,
    1816             :              const std::size_t arity,
    1817             :              const function_symbol& opid,
    1818             :              bracket_level_data& brackets,
    1819             :              std::stack<std::string>& auxiliary_code_fragments,
    1820             :              std::map<variable,std::string>& type_of_code_variables)
    1821             :   {
    1822        1527 :     const match_tree_S& treeS(tree);
    1823        1527 :     bool reset_current_data_parameters=false;
    1824        1527 :     if (atermpp::find_if(treeS.subtree(),matches(treeS.target_variable()))!=aterm_appl()) // treeS.target_variable occurs in treeS.subtree
    1825             :     {
    1826        1503 :       const std::string parameters = brackets.current_data_parameters.top(); 
    1827        1503 :       brackets.current_data_parameters.push(parameters + (parameters.empty()?"":", ") + "const data_expression& " + (std::string(treeS.target_variable().name()).c_str() + 1));
    1828        1503 :       const std::string arguments = brackets.current_data_arguments.top();
    1829        1503 :       brackets.current_data_arguments.push(arguments + (arguments.empty()?"":", ") + (std::string(treeS.target_variable().name()).c_str() + 1));
    1830        1503 :       reset_current_data_parameters=true;
    1831             : 
    1832        1503 :       if (level == 0)
    1833             :       {
    1834        1171 :         if (m_used[cur_arg])   
    1835             :         {
    1836         330 :           m_stream << m_padding << "const data_expression& " << std::string(treeS.target_variable().name()).c_str() + 1 << " = ";
    1837         330 :           m_stream << "arg" << cur_arg << "; // S1a\n";
    1838             :           
    1839         330 :           type_of_code_variables[treeS.target_variable()]="data_expression";
    1840             :         }
    1841             :         else
    1842             :         {
    1843         841 :           m_stream << m_padding << "const DATA_EXPR" << cur_arg <<"& " << std::string(treeS.target_variable().name()).c_str() + 1 << " = ";
    1844         841 :           m_stream << "arg_not_nf" << cur_arg << "; // S1b\n";
    1845         841 :           type_of_code_variables[treeS.target_variable()]="DATA_EXPR" + std::to_string(cur_arg);
    1846             :         }
    1847             :       }
    1848             :       else
    1849             :       {
    1850         332 :         m_stream << m_padding << "const data_expression& " << std::string(treeS.target_variable().name()).c_str() + 1 << " = ";
    1851             :         m_stream << "down_cast<data_expression>("
    1852         332 :                  << (level == 1 ? "arg" : "t") << parent << "[" << cur_arg << "]"
    1853         332 :                  << "); // S2\n";
    1854         332 :         type_of_code_variables[treeS.target_variable()]="data_expression";
    1855             :       }
    1856        1503 :     }
    1857        1527 :     implement_tree(m_stream, tree.subtree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1858        1527 :     if (reset_current_data_parameters)
    1859             :     {
    1860        1503 :       brackets.current_data_parameters.pop();
    1861        1503 :       brackets.current_data_arguments.pop();
    1862             :     }
    1863        1527 :   }
    1864             : 
    1865         368 :   void implement_treeM(
    1866             :              std::ostream& m_stream, 
    1867             :              const match_tree_M& tree, 
    1868             :              std::size_t cur_arg, 
    1869             :              std::size_t parent, 
    1870             :              std::size_t level, 
    1871             :              std::size_t cnt,
    1872             :              const std::size_t arity,
    1873             :              const function_symbol& opid,
    1874             :              bracket_level_data& brackets,
    1875             :              std::stack<std::string>& auxiliary_code_fragments,
    1876             :              std::map<variable,std::string>& type_of_code_variables)
    1877             :   {
    1878         368 :     m_stream << m_padding << "if (" << std::string(tree.match_variable().name()).c_str() + 1 << " == ";
    1879         368 :     if (level == 0)
    1880             :     {
    1881         335 :       m_stream << "arg" << cur_arg;
    1882             :     }
    1883             :     else
    1884             :     {
    1885          33 :       m_stream << (level == 1 ? "arg" : "t") << parent << "[" << cur_arg << "]";
    1886             :     }
    1887         368 :     m_stream << ") // M\n" << m_padding
    1888         368 :              << "{\n";
    1889         368 :     brackets.bracket_nesting_level++;
    1890         368 :     m_padding.indent();
    1891         368 :     implement_tree(m_stream, tree.true_tree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1892         368 :     m_padding.unindent();
    1893         368 :     brackets.bracket_nesting_level--;
    1894         368 :     m_stream << m_padding
    1895         368 :              << "}\n" << m_padding
    1896         368 :              << "else\n" << m_padding
    1897         368 :              << "{\n";
    1898         368 :     brackets.bracket_nesting_level++;
    1899         368 :     m_padding.indent();
    1900         368 :     implement_tree(m_stream, tree.false_tree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1901         368 :     m_padding.unindent();
    1902         368 :     brackets.bracket_nesting_level--;
    1903         368 :     m_stream << m_padding
    1904         368 :              << "}\n";
    1905         368 :   }
    1906             : 
    1907         852 :   void implement_treeF(
    1908             :              std::ostream& m_stream, 
    1909             :              const match_tree_F& tree, 
    1910             :              std::size_t cur_arg, 
    1911             :              std::size_t parent, 
    1912             :              std::size_t level, 
    1913             :              std::size_t cnt,
    1914             :              const std::size_t arity,
    1915             :              const function_symbol& opid,
    1916             :              bracket_level_data& brackets,
    1917             :              std::stack<std::string>& auxiliary_code_fragments,
    1918             :              std::map<variable,std::string>& type_of_code_variables)
    1919             :   {
    1920         852 :     bool reset_current_data_parameters=false;
    1921         852 :     const void* func = (void*)(atermpp::detail::address(tree.function()));
    1922         852 :     m_stream << m_padding;
    1923         852 :     brackets.bracket_nesting_level++;
    1924         852 :     if (level == 0)
    1925             :     {
    1926         740 :       if (!is_function_sort(tree.function().sort()))
    1927             :       {
    1928         519 :         m_stream << "if (uint_address(arg" << cur_arg << ") == " << func << ") // F1\n" << m_padding
    1929         519 :                  << "{\n";
    1930             :       }
    1931             :       else
    1932             :       {
    1933         221 :         m_stream << "if (uint_address((is_function_symbol(arg" << cur_arg <<  ") ? arg" << cur_arg << " : arg" << cur_arg << "[0])) == "
    1934         221 :                  << func << ") // F1\n" << m_padding
    1935         221 :                  << "{\n";
    1936             :       }
    1937             :     }
    1938             :     else
    1939             :     {
    1940         112 :       const char* arg_or_t = level == 1 ? "arg" : "t";
    1941         112 :       if (!is_function_sort(tree.function().sort()))
    1942             :       {
    1943         105 :         m_stream << "if (uint_address(" << arg_or_t << parent << "[" << cur_arg << "]) == "
    1944         105 :                  << func << ") // F2a " << tree.function().name() << "\n" << m_padding
    1945         105 :                  << "{\n" << m_padding
    1946         105 :                  << "  const data_expression& t" << cnt << " = down_cast<data_expression>(" << arg_or_t << parent << "[" << cur_arg << "]);\n";
    1947             :       }
    1948             :       else
    1949             :       {
    1950           7 :         m_stream << "if (is_application_no_check(down_cast<data_expression>(" << arg_or_t << parent << "[" << cur_arg << "])) && "
    1951           7 :                  <<     "uint_address(down_cast<data_expression>(" << arg_or_t << parent << "[" << cur_arg << "])[0]) == "
    1952           7 :                  << func << ") // F2b " << tree.function().name() << "\n" << m_padding
    1953           7 :                  << "{\n" << m_padding
    1954           7 :                  << "  const data_expression& t" << cnt << " = down_cast<data_expression>(" << arg_or_t << parent << "[" << cur_arg << "]);\n";
    1955             :       }
    1956         112 :       const std::string parameters = brackets.current_data_parameters.top();
    1957         112 :       brackets.current_data_parameters.push(parameters + (parameters.empty()?"":", ") + "const data_expression& t" + std::to_string(cnt));
    1958         112 :       const std::string arguments = brackets.current_data_arguments.top();
    1959         112 :       brackets.current_data_arguments.push(arguments + (arguments.empty()?"t":", t") + std::to_string(cnt));
    1960             : 
    1961         112 :       reset_current_data_parameters=true;
    1962         112 :     }
    1963         852 :     m_stack.push_back(cur_arg);
    1964         852 :     m_stack.push_back(parent);
    1965         852 :     m_padding.indent();
    1966         852 :     implement_tree(m_stream, tree.true_tree(), 1, level == 0 ? cur_arg : cnt, level + 1, cnt + 1, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1967         852 :     if (reset_current_data_parameters)
    1968             :     {
    1969         112 :       brackets.current_data_parameters.pop();
    1970         112 :       brackets.current_data_arguments.pop();
    1971             :     }
    1972         852 :     m_padding.unindent();
    1973         852 :     m_stack.pop_back();
    1974         852 :     m_stack.pop_back();
    1975         852 :     m_stream << m_padding
    1976         852 :              << "}\n" << m_padding
    1977         852 :              << "else\n" << m_padding
    1978         852 :              << "{\n";
    1979         852 :     m_padding.indent();
    1980         852 :     implement_tree(m_stream, tree.false_tree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    1981         852 :     m_padding.unindent();
    1982         852 :     m_stream << m_padding
    1983         852 :              << "}\n";
    1984         852 :     brackets.bracket_nesting_level--;
    1985         852 :   }
    1986             : 
    1987         584 :   void implement_treeD(
    1988             :              std::ostream& m_stream, 
    1989             :              const match_tree_D& tree, 
    1990             :              std::size_t level, 
    1991             :              std::size_t cnt,
    1992             :              const std::size_t arity,
    1993             :              const function_symbol& opid,
    1994             :              bracket_level_data& brackets,
    1995             :              std::stack<std::string>& auxiliary_code_fragments,
    1996             :              std::map<variable,std::string>& type_of_code_variables)
    1997             :   {
    1998         584 :     int i = m_stack.back();
    1999         584 :     m_stack.pop_back();
    2000         584 :     int j = m_stack.back();
    2001         584 :     m_stack.pop_back();
    2002         584 :     implement_tree(m_stream, tree.subtree(), j, i, level - 1, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2003         584 :     m_stack.push_back(j);
    2004         584 :     m_stack.push_back(i);
    2005         584 :   }
    2006             : 
    2007        1721 :   void implement_treeN(
    2008             :              std::ostream& m_stream, 
    2009             :              const match_tree_N& tree, 
    2010             :              std::size_t cur_arg, 
    2011             :              std::size_t parent, 
    2012             :              std::size_t level, 
    2013             :              std::size_t cnt,
    2014             :              const std::size_t arity,
    2015             :              const function_symbol& opid,
    2016             :              bracket_level_data& brackets,
    2017             :              std::stack<std::string>& auxiliary_code_fragments,
    2018             :              std::map<variable,std::string>& type_of_code_variables)
    2019             :   {
    2020        1721 :     implement_tree(m_stream, tree.subtree(), cur_arg + 1, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2021        1721 :   }
    2022             : 
    2023          58 :   void implement_treeC(
    2024             :              std::ostream& m_stream, 
    2025             :              const match_tree_C& tree, 
    2026             :              std::size_t cur_arg, 
    2027             :              std::size_t parent, 
    2028             :              std::size_t level, 
    2029             :              std::size_t cnt,
    2030             :              const std::size_t arity,
    2031             :              const function_symbol& opid,
    2032             :              bracket_level_data& brackets,
    2033             :              std::stack<std::string>& auxiliary_code_fragments, 
    2034             :              std::map<variable,std::string>& type_of_code_variables)
    2035             :   {
    2036          58 :     std::stringstream result_type_string;
    2037          58 :     calc_inner_term(m_stream, "result", tree.condition(), 0, true, result_type_string, type_of_code_variables);
    2038          58 :     m_stream << m_padding
    2039          58 :              << "if (result == sort_bool::true_()) // C\n" << m_padding
    2040          58 :              << "{\n";
    2041             : 
    2042          58 :     brackets.bracket_nesting_level++;
    2043          58 :     m_padding.indent();
    2044          58 :     implement_tree(m_stream, tree.true_tree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2045          58 :     m_padding.unindent();
    2046             : 
    2047          58 :     m_stream << m_padding
    2048          58 :              << "}\n" << m_padding
    2049          58 :              << "else\n" << m_padding
    2050          58 :              << "{\n";
    2051             : 
    2052          58 :     m_padding.indent();
    2053          58 :     implement_tree(m_stream, tree.false_tree(), cur_arg, parent, level, cnt, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2054          58 :     m_padding.unindent();
    2055             : 
    2056          58 :     m_stream << m_padding
    2057          58 :              << "}\n";
    2058          58 :     brackets.bracket_nesting_level--;
    2059          58 :   }
    2060             : 
    2061        1251 :   void implement_treeR(
    2062             :              std::ostream& m_stream, 
    2063             :              const match_tree_R& tree, 
    2064             :              std::size_t cur_arg, 
    2065             :              std::size_t level,
    2066             :              const std::map<variable,std::string>& type_of_code_variables)
    2067             :   {
    2068        1251 :     if (level > 0)
    2069             :     {
    2070         399 :       cur_arg = m_stack[2 * level - 1];
    2071             :     }
    2072             :     
    2073        1251 :     std::stringstream result_type_string;
    2074        1251 :     calc_inner_term(m_stream, "result", tree.result(), cur_arg + 1, true, result_type_string, type_of_code_variables);
    2075        1251 :     m_stream << m_padding << "this_rewriter->m_rewrite_stack.reset_stack_size(old_stack_size);\n" 
    2076        1251 :              << m_padding << "return; // R1 " << tree.result() << "\n"; 
    2077        1251 :   }
    2078             : 
    2079           0 :   const match_tree& implement_treeC(
    2080             :              std::ostream& m_stream, 
    2081             :              const match_tree_C& tree,
    2082             :              bracket_level_data& brackets,
    2083             :              const std::map<variable,std::string>& type_of_code_variables)
    2084             :   {
    2085           0 :     std::stringstream result_type_string;
    2086           0 :     assert(tree.true_tree().isR());
    2087           0 :     calc_inner_term(m_stream, "result", tree.condition(), 0, true, result_type_string, type_of_code_variables);
    2088           0 :     m_stream << ";\n" << m_padding
    2089           0 :              << "if (result == sort_bool::true_()) // C\n" << m_padding
    2090           0 :              << "{\n";
    2091           0 :     brackets.bracket_nesting_level++;
    2092           0 :     calc_inner_term(m_stream, "result", match_tree_R(tree.true_tree()).result(), 0, true, result_type_string, type_of_code_variables);
    2093           0 :     m_stream << ";\n" 
    2094           0 :              << m_padding << "this_rewriter->m_rewrite_stack.reset_stack_size(old_stack_size);\n" 
    2095           0 :              << m_padding << "return ";
    2096           0 :     brackets.bracket_nesting_level--;
    2097           0 :     m_stream << ";\n" << m_padding
    2098           0 :              << "}\n" << m_padding
    2099           0 :              << "else\n" << m_padding
    2100           0 :              << "{\n" << m_padding;
    2101           0 :     m_padding.indent();
    2102           0 :     return tree.false_tree();
    2103           0 :   }
    2104             : 
    2105           0 :   void implement_treeR(
    2106             :              std::ostream& m_stream, 
    2107             :              const match_tree_R& tree, 
    2108             :              std::size_t arity,
    2109             :              const std::map<variable,std::string>& type_of_code_variables)
    2110             :   {
    2111           0 :     std::stringstream result_type_string;
    2112           0 :     if (arity == 0)
    2113             :     {
    2114           0 :       calc_inner_term(m_stream, "result", tree.result(), 0, true, result_type_string, type_of_code_variables);
    2115           0 :       m_stream << ";\n" << m_padding
    2116           0 :                << m_padding << "this_rewriter->m_rewrite_stack.reset_stack_size(old_stack_size);\n" 
    2117           0 :                << m_padding << "return; // R2a\n";
    2118             :     }
    2119             :     else
    2120             :     {
    2121             :       // arity>0
    2122           0 :       calc_inner_term(m_stream, "result", tree.result(), 0, true, result_type_string, type_of_code_variables);
    2123           0 :       m_stream << ";\n" 
    2124           0 :                << m_padding << "this_rewriter->m_rewrite_stack.reset_stack_size(old_stack_size);\n" 
    2125           0 :                << m_padding << "return; // R2b\n";
    2126             :     }
    2127           0 :   }
    2128             : 
    2129             : public:
    2130           5 :   ImplementTree(RewriterCompilingJitty& rewr, function_symbol_vector& function_symbols)
    2131           5 :     : m_rewriter(rewr), m_padding(2)
    2132             :   {
    2133         445 :     for (function_symbol_vector::const_iterator it = function_symbols.begin(); it != function_symbols.end(); ++it)
    2134             :     {
    2135         440 :       const std::size_t max_arity = getArity(*it);
    2136        1816 :       for (std::size_t arity = 0; arity <= max_arity; ++arity)
    2137             :       {
    2138        1376 :         if (arity_is_allowed(it->sort(), arity))
    2139             :         {
    2140             :           // Register this <symbol, arity, nfs> tuple as a function that needs to be generated
    2141         897 :           static_cast<void>(rewr_function_name(*it, arity));
    2142             :         }
    2143             :       }
    2144             :     }
    2145           5 :   }
    2146             : 
    2147           5 :   const std::set<rewr_function_spec>& implemented_rewrs()
    2148             :   {
    2149           5 :     return m_rewr_functions_implemented;
    2150             :   }
    2151             : 
    2152             :   ///
    2153             :   /// \brief implement_tree
    2154             :   /// \param tree
    2155             :   /// \param arity
    2156             :   ///
    2157         640 :   void implement_tree(
    2158             :              std::ostream& m_stream, 
    2159             :              match_tree tree, 
    2160             :              const std::size_t arity,
    2161             :              const function_symbol& opid,
    2162             :              bracket_level_data& brackets,
    2163             :              std::stack<std::string>& auxiliary_code_fragments,
    2164             :              std::map<variable,std::string>& type_of_code_variables)
    2165             :   {
    2166             :     /* for (std::size_t i = 0; i < arity; ++i)
    2167             :     {
    2168             :       if (!m_used[i])
    2169             :       {
    2170             :         m_nnfvars.push_front(atermpp::aterm_int(i));
    2171             :       }
    2172             :     } */
    2173             : 
    2174         640 :     std::size_t l = 0;
    2175         640 :     while (tree.isC())
    2176             :     {
    2177           0 :       tree = implement_treeC(m_stream, down_cast<match_tree_C>(tree),brackets, type_of_code_variables);
    2178           0 :       l++;
    2179             :     }
    2180             : 
    2181         640 :     if (tree.isR())
    2182             :     {
    2183           0 :       implement_treeR(m_stream, down_cast<match_tree_R>(tree), arity, type_of_code_variables);
    2184             :     }
    2185             :     else
    2186             :     {
    2187         640 :       implement_tree(m_stream, tree, 0, 0, 0, 0, arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2188             :     }
    2189             : 
    2190             :     // Close braces opened by implement_tree(std ostream&, onst match_tree_C&)
    2191         640 :     while (0 < l--)
    2192             :     {
    2193           0 :       m_padding.unindent();
    2194           0 :       m_stream << m_padding << "}\n";
    2195             :     }
    2196         640 :   }
    2197             : 
    2198           2 :   std::string implement_body_of_cplusplus_defined_function(
    2199             :              const std::size_t arity,
    2200             :              const std::string& target_for_output,
    2201             :              const std::string& head,
    2202             :              const function_sort& s,
    2203             :              std::size_t& used_arguments)
    2204             :   {
    2205             :     // In this case opid is used in a higher order fashion. 
    2206           2 :     assert(!target_for_output.empty());
    2207           2 :     const std::size_t domain_size = s.domain().size();
    2208           2 :     std::stringstream ss;
    2209           2 :     ss << m_padding << appl_function(domain_size) << "(" << target_for_output << "," << head;
    2210             : 
    2211           4 :     for (std::size_t i = 0; i < domain_size; ++i)
    2212             :     {
    2213           2 :         ss << ", [&](data_expression& r){ local_rewrite(r, arg_not_nf" << used_arguments + i << "); }";
    2214             :     }
    2215           2 :     ss << ");\n";
    2216             : 
    2217           2 :     used_arguments += domain_size;
    2218           2 :     if (used_arguments<arity)
    2219             :     {
    2220           0 :       return ss.str() + implement_body_of_cplusplus_defined_function(arity,
    2221             :                                                           target_for_output,
    2222             :                                                           target_for_output,
    2223             :                                                           down_cast<function_sort>(s.codomain()), 
    2224           0 :                                                           used_arguments);
    2225             :     }
    2226             :     else
    2227             :     {
    2228           2 :       return ss.str();
    2229             :     }
    2230           2 :   };
    2231             : 
    2232           6 :   void implement_a_cplusplus_defined_function(
    2233             :              std::ostream& m_stream,
    2234             :              const std::string& target_for_output,
    2235             :              std::size_t arity,
    2236             :              const function_symbol& opid,
    2237             :              const data_specification& data_spec)
    2238             :   {
    2239           6 :     m_stream << m_padding << "// Implement function " << opid << " by calling a user defined rewrite function.\n";
    2240             :     
    2241             :     /* m_stream << m_padding << "stack_increment++;\n"
    2242             :              << m_padding << "this_rewriter->m_rewrite_stack.increase(1);\n"
    2243             :              << m_padding << "data_expression& local_store=this_rewriter->m_rewrite_stack.top();\n"; */
    2244             : 
    2245           6 :     m_stream << m_padding << "data_expression& local_store=this_rewriter->m_rewrite_stack.new_stack_position();\n";
    2246             : 
    2247           6 :     const std::string cplusplus_function_name = data_spec.cpp_implemented_functions().find(opid)->second.second;
    2248             : 
    2249             :     // First calculate the core function, which may be surrounded by extra applications. 
    2250           6 :     std::stringstream ss;
    2251           6 :     ss << cplusplus_function_name << "(";
    2252             :     
    2253          20 :     for(size_t i=0; i<get_direct_arity(opid); ++i)
    2254             :     {
    2255          14 :       ss << (i>0?",":"");
    2256          14 :       ss << "local_rewrite(arg_not_nf" << i << ")";
    2257             :     }
    2258           6 :     ss << ")";
    2259             : 
    2260           6 :     if (arity==get_direct_arity(opid))
    2261             :     {
    2262           4 :       if (target_for_output.empty())
    2263             :       {
    2264           0 :         m_stream << ss.str();
    2265             :       }
    2266             :       else
    2267             :       {
    2268             :         // m_stream << m_padding << target_for_output << " = " << ss.str() << ";\n";
    2269           8 :         m_stream << m_padding << target_for_output << ".assign(" << ss.str() 
    2270           4 :                  << ", *this_rewriter->m_thread_aterm_pool);\n";
    2271             :       }
    2272           4 :       return;
    2273             :     }
    2274             :     // else it is a higher order function, and it must be surrounded by "application"s. 
    2275           2 :     assert(arity>get_direct_arity(opid));
    2276           2 :     std::size_t used_arguments = get_direct_arity(opid);
    2277           2 :     std::string result="local_store";
    2278           8 :     m_stream << m_padding << implement_body_of_cplusplus_defined_function(
    2279             :                                          arity,
    2280             :                                          result,
    2281           4 :                                          ss.str(), 
    2282           2 :                                          down_cast<function_sort>(down_cast<function_sort>(opid.sort()).codomain()),
    2283           2 :                                          used_arguments) << ";\n";
    2284           2 :     assert(used_arguments == arity);
    2285             :    
    2286             :     // If there applications surrounding the term, it may not be a normalform anymore, but its arguments
    2287             :     // are in normal form. That is why rewrite_aux has as second argument true. 
    2288           2 :     if (target_for_output.empty())
    2289             :     {
    2290           0 :       m_stream << m_padding << "data_expression result1; // TODO: optimize\n"
    2291           0 :                << m_padding << "rewrite_aux<true>(result1, " << result << ",this_rewriter);\n";
    2292             :     }
    2293             :     else
    2294             :     {
    2295           2 :       m_stream << m_padding << "rewrite_aux<true>(" << target_for_output << ", " << result << ",this_rewriter);\n";
    2296             :     }
    2297          10 :   }
    2298             : 
    2299         897 :   void implement_strategy(
    2300             :              std::ostream& m_stream, 
    2301             :              match_tree_list strat, 
    2302             :              std::size_t arity, 
    2303             :              const function_symbol& opid,
    2304             :              bracket_level_data& brackets,
    2305             :              std::stack<std::string>& auxiliary_code_fragments,
    2306             :              const data_specification& data_spec)
    2307             :   {
    2308             :     // First check whether this is a predefined function with the right arity. 
    2309         907 :     if (data_spec.cpp_implemented_functions().find(opid)!=data_spec.cpp_implemented_functions().end() &&
    2310          10 :         arity>=get_direct_arity(opid))
    2311             :     {
    2312           6 :       implement_a_cplusplus_defined_function(m_stream, "result", arity, opid, data_spec);
    2313           6 :       return;
    2314             :     }
    2315         891 :     bool added_new_parameters_in_brackets=false;
    2316         891 :     m_used=nfs_array(arity); // This vector maintains which arguments are in normal form.
    2317             :     // m_nnfvars=variable_or_number_list();
    2318         891 :     std::map<variable,std::string> type_of_code_variables;
    2319        2253 :     while (!strat.empty())
    2320             :     {
    2321        1362 :       m_stream << m_padding << "// " << strat.front() <<  "\n";
    2322        1362 :       if (strat.front().isA())
    2323             :       {
    2324         722 :         std::size_t arg = match_tree_A(strat.front()).variable_index();
    2325         722 :         if (!m_used[arg])
    2326             :         {
    2327             :           // m_stream << m_padding << "const data_expression& arg" << arg << " = local_rewrite(arg_not_nf" << arg << ");\n"; 
    2328             :           /* m_stream << m_padding << "data_expression& arg" << arg << " = this_rewriter->m_rewrite_stack.new_stack_position();\n"
    2329             :                    << m_padding << "local_rewrite(arg" << arg << ", arg_not_nf" << arg << ");\n"; */
    2330             :        
    2331         722 :           m_stream << m_padding << "data_expression& arg" << arg 
    2332         722 :                    << "(std::is_convertible<DATA_EXPR" << arg << ", const data_expression&>::value?(const_cast<data_expression&>(reinterpret_cast<const data_expression&>(arg_not_nf" << arg << "))):this_rewriter->m_rewrite_stack.new_stack_position());\n"
    2333         722 :                    << m_padding << "if constexpr (!std::is_convertible<DATA_EXPR" << arg << ", const data_expression&>::value)\n"
    2334         722 :                    << m_padding << "{\n"
    2335         722 :                    << m_padding << "  local_rewrite(arg" << arg << ", arg_not_nf" << arg << ");\n"
    2336         722 :                    << m_padding << "}\n";
    2337         722 :           m_used[arg] = true;
    2338         722 :           if (!added_new_parameters_in_brackets)
    2339             :           {
    2340         319 :             added_new_parameters_in_brackets=true;
    2341         319 :             brackets.current_data_parameters.push(brackets.current_data_parameters.top()); 
    2342         319 :             brackets.current_data_arguments.push(brackets.current_data_arguments.top()); 
    2343             :           }
    2344         722 :           const std::string& parameters=brackets.current_data_parameters.top();
    2345         722 :           brackets.current_data_parameters.top()=parameters + (parameters.empty()?"":", ") + "const data_expression& arg" + std::to_string(arg);
    2346         722 :           const std::string arguments = brackets.current_data_arguments.top();
    2347         722 :           brackets.current_data_arguments.top()=arguments + (arguments.empty()?"":", ") + "arg" + std::to_string(arg);
    2348         722 :         }
    2349         722 :         m_stream << m_padding << "// Considering argument " << arg << "\n";
    2350             :       }
    2351             :       else
    2352             :       {
    2353         640 :         m_stream << m_padding << "{\n";
    2354         640 :         m_padding.indent();
    2355         640 :         implement_tree(m_stream, strat.front(), arity, opid, brackets, auxiliary_code_fragments, type_of_code_variables);
    2356         640 :         m_padding.unindent();
    2357         640 :         m_stream << m_padding << "}\n";
    2358             :       }
    2359        1362 :       strat = strat.tail();
    2360             :     }
    2361         891 :     rewr_function_finish(m_stream, arity, opid);
    2362         891 :     if (added_new_parameters_in_brackets)
    2363             :     {
    2364         319 :       brackets.current_data_parameters.pop();
    2365         319 :       brackets.current_data_arguments.pop();
    2366             :     }
    2367         891 :   }
    2368             : 
    2369        2472 :   std::string get_heads(const sort_expression& s, const std::string& base_string, const std::size_t number_of_arguments)
    2370             :   {
    2371        2472 :     std::stringstream ss;
    2372        2472 :     if (is_function_sort(s) && number_of_arguments>0)
    2373             :     {
    2374         300 :       const function_sort fs(s);
    2375         300 :       ss << "down_cast<application>(" << get_heads(fs.codomain(),base_string,number_of_arguments-fs.domain().size()) << ".head())";
    2376         300 :       return ss.str();
    2377         300 :     }
    2378        2172 :     return base_string;
    2379        2472 :   }
    2380             : 
    2381             :   ///
    2382             :   /// \brief get_recursive_argument provides the index-th argument of an expression provided in
    2383             :   ///        base_string, given that its head symbol has type s and there are number_of_arguments
    2384             :   ///        arguments. Example: if f:D->E->F and index is 0, base_string is "t", base_string is
    2385             :   ///        set to "atermpp::down_cast<application>(t[0])[0]
    2386             :   /// \param s
    2387             :   /// \param index
    2388             :   /// \param base_string
    2389             :   /// \param number_of_arguments
    2390             :   /// \return
    2391             :   ///
    2392        2172 :   void get_recursive_argument(std::ostream& m_stream, function_sort s, std::size_t index, const std::string& base_string, std::size_t number_of_arguments)
    2393             :   {
    2394        2340 :     while (index >= s.domain().size())
    2395             :     {
    2396         168 :       assert(is_function_sort(s.codomain()));
    2397         168 :       index -= s.domain().size();
    2398         168 :       number_of_arguments -= s.domain().size();
    2399         168 :       s = down_cast<function_sort>(s.codomain());
    2400             :     }
    2401        2172 :     m_stream << get_heads(s.codomain(), base_string, number_of_arguments - s.domain().size()) << "[" << index << "]";
    2402        2172 :   }
    2403             : 
    2404           5 :   void generate_delayed_application_functions(std::ostream& ss)
    2405             :   {
    2406          17 :     for(std::size_t arity: m_delayed_application_functions)
    2407             :     {
    2408          12 :       assert(arity>0);
    2409          12 :       ss << m_padding << "template < class HEAD";
    2410          33 :       for (std::size_t i = 0; i < arity; ++i)
    2411             :       {
    2412          21 :         ss << ", class DATA_EXPR" << i;
    2413             :       }
    2414          12 :       ss << " >\n";
    2415             : 
    2416          12 :       ss << m_padding << "class delayed_application" << arity << "\n"
    2417          12 :          << m_padding << "{\n";
    2418          12 :       m_padding.indent();
    2419          12 :       ss << m_padding << "protected:\n";
    2420          12 :       m_padding.indent();
    2421             : 
    2422          12 :       ss << m_padding << "const HEAD& m_head;\n";
    2423          33 :       for (std::size_t i = 0; i < arity; ++i)
    2424             :       {
    2425          21 :         ss  << m_padding << "const DATA_EXPR" << i << "& m_arg" << i << ";\n";
    2426             :       }
    2427          12 :       ss << m_padding << "RewriterCompilingJitty* this_rewriter;\n\n";
    2428          12 :       m_padding.unindent();
    2429          12 :       ss << m_padding << "public:\n";
    2430          12 :       m_padding.indent();
    2431             : 
    2432          12 :       ss << m_padding << "delayed_application" << arity << "(const HEAD& head";
    2433          33 :       for (std::size_t i = 0; i < arity; ++i)
    2434             :       {
    2435          21 :         ss << ", const DATA_EXPR" << i << "& arg" << i;
    2436             :       }
    2437          12 :       ss << ", RewriterCompilingJitty* tr)\n";
    2438          12 :       ss << m_padding << "  : m_head(head)";
    2439             : 
    2440          33 :       for (std::size_t i = 0; i < arity; ++i)
    2441             :       {
    2442          21 :         ss << ", m_arg" << i << "(arg" << i << ")";
    2443             :       }
    2444          12 :       ss << ", this_rewriter(tr)\n" << m_padding << "{}\n\n";
    2445             : 
    2446          12 :       ss << m_padding << "data_expression& normal_form() const\n";
    2447          12 :       ss << m_padding << "{\n";
    2448          12 :       m_padding.indent();
    2449             : 
    2450          12 :       ss << m_padding << "data_expression& local_store=this_rewriter->m_rewrite_stack.new_stack_position();\n"
    2451          12 :          << m_padding << appl_function(arity) << "(local_store, [&](data_expression& r){ local_rewrite(r, m_head); }";
    2452             :       /* ss << m_padding << "this_rewriter->m_rewrite_stack.increase(1);\n"
    2453             :          << m_padding << "data_expression& local_store=this_rewriter->m_rewrite_stack.top();\n"
    2454             :          << m_padding << "stack_increment++;\n"
    2455             :          << m_padding << appl_function(arity) << "(local_store, [&](data_expression& r){ local_rewrite(r, m_head); }"; */
    2456          33 :       for (std::size_t i = 0; i < arity; ++i)
    2457             :       {
    2458          21 :         ss << ", [&](data_expression& r){ local_rewrite(r, m_arg" << i << "); }";
    2459             :       }
    2460          12 :       ss << ");\n";
    2461          12 :       ss << m_padding << "rewrite_with_arguments_in_normal_form(local_store, local_store, this_rewriter);\n"
    2462          12 :          << m_padding << "return local_store;\n";
    2463             : 
    2464          12 :       m_padding.unindent();
    2465          12 :       ss << m_padding << "}\n\n";
    2466             : 
    2467          12 :       ss << m_padding << "void normal_form(data_expression& result) const\n";
    2468          12 :       ss << m_padding << "{\n";
    2469          12 :       m_padding.indent();
    2470             : 
    2471          12 :       ss << m_padding << appl_function(arity) << "(result, [&](data_expression& result){ local_rewrite(result, m_head); }";
    2472          33 :       for (std::size_t i = 0; i < arity; ++i)
    2473             :       {
    2474          21 :         ss << ", [&](data_expression& result){ local_rewrite(result, m_arg" << i << "); }";
    2475             :       }
    2476          12 :       ss << ");\n";
    2477          12 :       ss << m_padding << "rewrite_with_arguments_in_normal_form(result, result, this_rewriter);\n";
    2478             : 
    2479          12 :       m_padding.unindent();
    2480          12 :       ss << m_padding << "}\n\n";
    2481          12 :       m_padding.unindent();
    2482          12 :       m_padding.unindent();
    2483          12 :       ss << m_padding <<  "};\n\n";
    2484             :     }
    2485             : 
    2486           5 :   }
    2487             : 
    2488         451 :   void rewr_function_finish_term(std::ostream& m_stream, 
    2489             :                                  const std::size_t arity, 
    2490             :                                  const std::string& head, 
    2491             :                                  const function_sort& s)
    2492             :   {
    2493         451 :     if (arity == 0)
    2494             :     {
    2495           0 :       m_stream << m_padding << "result = " << head << ";\n";
    2496           0 :       return;
    2497             :     }
    2498             : 
    2499         451 :     sort_expression current_sort=s;
    2500         451 :     std::size_t used_arguments=0;
    2501         950 :     while (used_arguments<arity)
    2502             :     {
    2503         499 :       assert(is_function_sort(current_sort)); // otherwise used_arguments == arity == 0, excluded above. 
    2504         499 :       const function_sort& fs = atermpp::down_cast<function_sort>(current_sort);
    2505         499 :       const std::size_t domain_size = fs.domain().size();
    2506         499 :       current_sort = fs.codomain();
    2507             :       
    2508         499 :       m_stream << m_padding << appl_function(domain_size) << "(result, ";
    2509         499 :       if (used_arguments>0)
    2510             :       {  
    2511          48 :         m_stream << "result";
    2512             :       }
    2513             :       else
    2514             :       {
    2515         451 :         m_stream << head;
    2516             :       }
    2517             : 
    2518        1569 :       for (std::size_t i = 0; i < domain_size; ++i)
    2519             :       {
    2520        1070 :         if (m_used[used_arguments + i])
    2521             :         {
    2522         722 :           m_stream << ", arg" << used_arguments + i;
    2523             :         }
    2524             :         else
    2525             :         {
    2526         348 :           m_stream << ", [&](data_expression& result){ local_rewrite(result, arg_not_nf" << used_arguments + i << "); }";
    2527             :         }
    2528             :       }
    2529         499 :       m_stream << ");\n";
    2530         499 :       used_arguments += domain_size;
    2531             :     }
    2532         451 :     assert(used_arguments==arity);
    2533         451 :   }
    2534             : 
    2535             : 
    2536         891 :   void rewr_function_finish(std::ostream& m_stream, std::size_t arity, const data::function_symbol& opid)
    2537             :   {
    2538             :     // Note that arity is the total arity, of all function symbols.
    2539         891 :     if (arity == 0)
    2540             :     {
    2541         440 :       m_stream << m_padding << "result.unprotected_assign<false>(";
    2542         440 :       RewriterCompilingJitty::substitution_type sigma;
    2543         440 :       m_stream << m_rewriter.m_nf_cache->insert(m_rewriter.jitty_rewriter(opid,sigma)) << ");\n";
    2544         440 :     }
    2545             :     else
    2546             :     {
    2547         451 :       std::stringstream ss;
    2548         451 :       ss << "this_rewriter->normal_forms_for_constants[" 
    2549         451 :          << atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::index(opid) 
    2550         451 :          << "]";
    2551         451 :       rewr_function_finish_term(m_stream, arity, ss.str(), down_cast<function_sort>(opid.sort()));
    2552         451 :     } 
    2553         891 :   }
    2554             : 
    2555         897 :   void rewr_function_signature(std::ostream& m_stream, std::size_t index, std::size_t arity, bracket_level_data& brackets)
    2556             :   {
    2557             :     // Constant function symbols (a == 0) can be passed by reference
    2558         897 :     if (arity>0)
    2559             :     {
    2560         457 :       m_stream << m_padding << "template < ";
    2561         457 :       std::stringstream s;
    2562        1543 :       for (std::size_t i = 0; i < arity; ++i)
    2563             :       {
    2564             :         
    2565             :         s << (i == 0 ? "" : ", ")
    2566        1086 :                  << "class DATA_EXPR" << i;
    2567             :       }
    2568         457 :       m_stream << s.str() << ">\n";
    2569         457 :       brackets.current_template_parameters = s.str();
    2570         457 :     }
    2571         897 :     m_stream << m_padding << "static inline void"
    2572         897 :              << " rewr_" << index << "_" << arity << "(data_expression& result";
    2573             : 
    2574         897 :     std::stringstream arguments;
    2575         897 :     std::stringstream parameters;
    2576        1983 :     for (std::size_t i = 0; i < arity; ++i)
    2577             :     {
    2578        1086 :       parameters << ", const DATA_EXPR" << i << "& arg_not_nf"
    2579        1086 :                  << i;
    2580        1086 :       arguments  << (i == 0 ? "" : ", ") << "arg_not_nf" << i;
    2581             :     }
    2582         897 :     m_stream << parameters.str() << ", RewriterCompilingJitty* this_rewriter)\n";
    2583         897 :     brackets.current_data_arguments.push(arguments.str());
    2584         897 :     brackets.current_data_parameters.push(parameters.str());
    2585         897 :   }
    2586             : 
    2587         897 :   void rewr_function_implementation(
    2588             :              std::ostream& m_stream, 
    2589             :              const data::function_symbol& func, 
    2590             :              std::size_t arity, 
    2591             :              match_tree_list strategy,
    2592             :              const data_specification& data_spec)
    2593             : 
    2594             :   {
    2595         897 :     bracket_level_data brackets;
    2596         897 :     std::stack<std::string> auxiliary_code_fragments;
    2597             : 
    2598         897 :     std::size_t index = atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::index(func);
    2599         897 :     m_stream << m_padding << "// [" << index << "] " << func << ": " << func.sort() << "\n";
    2600         897 :     rewr_function_signature(m_stream, index, arity, brackets);
    2601         897 :     m_stream << m_padding << "{\n"
    2602         897 :              << m_padding << "  mcrl2::utilities::mcrl2_unused(this_rewriter); // Suppress warning\n"
    2603         897 :              << m_padding << "  std::size_t old_stack_size=this_rewriter->m_rewrite_stack.stack_size();\n";
    2604         897 :     m_padding.indent();
    2605         897 :     implement_strategy(m_stream, strategy, arity, func, brackets, auxiliary_code_fragments,data_spec);
    2606         897 :     m_stream << m_padding << "this_rewriter->m_rewrite_stack.reset_stack_size(old_stack_size);\n"
    2607         897 :              << m_padding << "return;\n";
    2608         897 :     m_padding.unindent();
    2609         897 :     m_stream << m_padding << "}\n\n";
    2610             : 
    2611         897 :     if (arity>0)
    2612             :     {
    2613         457 :       m_stream << m_padding <<
    2614         457 :                     "static inline void rewr_" << index << "_" << arity << "_term" 
    2615             :                     "(data_expression& result, const application&" << (arity == 0 ? "" : " t") << ", RewriterCompilingJitty* this_rewriter) "
    2616         457 :                     "{ rewr_" << index << "_" << arity << "(result";
    2617        1543 :       for(std::size_t i = 0; i < arity; ++i)
    2618             :       {
    2619        1086 :         assert(is_function_sort(func.sort()));
    2620        1086 :         m_stream << ", term_not_in_normal_form(";
    2621        1086 :         get_recursive_argument(m_stream, down_cast<function_sort>(func.sort()), i, "t", arity);
    2622        1086 :         m_stream << ", this_rewriter)";
    2623             :       }
    2624         457 :       m_stream << ", this_rewriter); }\n\n";
    2625             : 
    2626         457 :       m_stream << m_padding <<
    2627         457 :                     "static inline void rewr_" << index << "_" << arity << "_term_arg_in_normal_form" 
    2628             :                     "(data_expression& result, const application&" << (arity == 0 ? "" : " t") << ", RewriterCompilingJitty* this_rewriter) "
    2629         457 :                     "{ rewr_" << index << "_" << arity << "(result";
    2630        1543 :       for(std::size_t i = 0; i < arity; ++i)
    2631             :       {
    2632        1086 :         assert(is_function_sort(func.sort()));
    2633        1086 :         m_stream << ", ";
    2634        1086 :         get_recursive_argument(m_stream, down_cast<function_sort>(func.sort()), i, "t", arity);
    2635             :       }
    2636         457 :       m_stream << ", this_rewriter); }\n\n";
    2637             :     }
    2638             : 
    2639         897 :     while (!auxiliary_code_fragments.empty())
    2640             :     {
    2641           0 :       m_stream << auxiliary_code_fragments.top();
    2642           0 :       auxiliary_code_fragments.pop();
    2643             :     }
    2644         897 :     m_stream << "\n";
    2645         897 :   }
    2646             : 
    2647         128 :   void generate_delayed_normal_form_generating_function(std::ostream& m_stream, const data::function_symbol& func, std::size_t arity)
    2648             :   {
    2649         128 :     std::size_t index = atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::index(func);
    2650         128 :     m_stream << m_padding << "// [" << index << "] " << func << ": " << func.sort() << "\n";
    2651         128 :     if (arity>0)
    2652             :     {
    2653         128 :       m_stream << m_padding << "template < ";
    2654         363 :       for (std::size_t i = 0; i < arity; ++i)
    2655             :       {
    2656             :         m_stream << (i == 0 ? "" : ", ")
    2657         235 :                  << "class DATA_EXPR" << i;
    2658             :       }
    2659         128 :       m_stream << ">\n";
    2660             :     }
    2661         128 :     m_stream << m_padding << "class delayed_rewr_" << index << "_" << arity << "\n";
    2662         128 :     m_stream << m_padding << "{\n";
    2663         128 :     m_padding.indent();
    2664         128 :     m_stream << m_padding << "protected:\n";
    2665         128 :     m_padding.indent();
    2666         363 :     for(std::size_t i = 0; i < arity; ++i)
    2667             :     {
    2668         235 :       m_stream << m_padding << "const DATA_EXPR" << i << "& m_t" << i << ";\n";
    2669             :     }
    2670         128 :     m_stream << m_padding << "RewriterCompilingJitty* this_rewriter;\n";
    2671         128 :     m_padding.unindent();
    2672         128 :     m_stream << m_padding << "public:\n";
    2673         128 :     m_padding.indent();
    2674         128 :     m_stream << m_padding << "delayed_rewr_" << index << "_" << arity << "(";
    2675         363 :     for(std::size_t i = 0; i < arity; ++i)
    2676             :     {
    2677         235 :       m_stream << (i==0?"":", ") << "const DATA_EXPR" << i << "& t" << i;
    2678             :     }
    2679         128 :     m_stream << (arity == 0 ? "" : ", ") << "RewriterCompilingJitty* tr)\n";
    2680         128 :     m_stream << m_padding << (arity==0?"":"  : ");
    2681         363 :     for(std::size_t i = 0; i < arity; ++i)
    2682             :     {
    2683         235 :       m_stream << (i==0?"":", ") << "m_t" << i << "(t" << i << ")";
    2684             :     }
    2685             :     m_stream << (arity==0?"":", ") << "this_rewriter(tr)"
    2686         128 :              << (arity==0?"":"\n") << m_padding << "{}\n\n"
    2687         128 :              << m_padding << "data_expression& normal_form() const\n"
    2688         128 :              << m_padding << "{\n"
    2689             : /*             << m_padding << "  this_rewriter->m_rewrite_stack.increase(1);\n"
    2690             :              << m_padding << "  data_expression& local_store=this_rewriter->m_rewrite_stack.top();\n"
    2691             :              << m_padding << "  stack_increment++;\n" */
    2692         128 :              << m_padding << "  data_expression& local_store=this_rewriter->m_rewrite_stack.new_stack_position();\n"
    2693         128 :              << m_padding << "  rewr_" << index << "_" << arity << "(local_store";
    2694         363 :     for(std::size_t i = 0; i < arity; ++i)
    2695             :     {
    2696         235 :       m_stream << ", m_t" << i;
    2697             :     }
    2698             : 
    2699         128 :     m_stream << (arity==0?"":", ") << "this_rewriter);\n"
    2700         128 :              << m_padding << "  return local_store;\n"
    2701         128 :              << m_padding << "}\n";
    2702             : 
    2703         128 :     m_stream << m_padding << "void normal_form(data_expression& result) const\n"
    2704         128 :              << m_padding << "{\n"
    2705         128 :              << m_padding << "  rewr_" << index << "_" << arity << "(result";
    2706         363 :     for(std::size_t i = 0; i < arity; ++i)
    2707             :     {
    2708         235 :       m_stream << ", m_t" << i;
    2709             :     }
    2710             : 
    2711         128 :     m_stream << (arity==0?"":", ") << "this_rewriter);\n"
    2712         128 :              << m_padding << "}\n";
    2713             : 
    2714         128 :     m_padding.unindent();
    2715         128 :     m_padding.unindent();
    2716         128 :     m_stream << m_padding << "};\n";
    2717         128 :     m_stream << m_padding << "\n";
    2718         128 :   }
    2719             : 
    2720           5 :   void generate_rewr_functions(std::ostream& m_stream, const data_specification& data_spec)
    2721             :   {
    2722        1030 :     while (!m_rewr_functions.empty())
    2723             :     {
    2724        1025 :       rewr_function_spec spec = m_rewr_functions.top();
    2725        1025 :       m_rewr_functions.pop();
    2726        1025 :       if (spec.delayed())
    2727             :       {
    2728         128 :         generate_delayed_normal_form_generating_function(m_stream, spec.fs(), spec.arity());
    2729             :       }
    2730             :       else
    2731             :       {
    2732         897 :         const match_tree_list strategy = m_rewriter.create_strategy(m_rewriter.jittyc_eqns[spec.fs()], spec.arity());
    2733         897 :         rewr_function_implementation(m_stream, spec.fs(), spec.arity(), strategy, data_spec);
    2734         897 :       }
    2735        1025 :     }
    2736           5 :   }
    2737             : };
    2738             : 
    2739          10 : void RewriterCompilingJitty::CleanupRewriteSystem()
    2740             : {
    2741             :   // m_nf_cache.clear();
    2742          10 :   if (so_rewr_cleanup != nullptr)
    2743             :   {
    2744           5 :     so_rewr_cleanup();
    2745             :   }
    2746          10 : }
    2747             : 
    2748             : ///
    2749             : /// \brief generate_cpp_filename creates a filename that is hopefully unique enough not to cause
    2750             : ///        name clashes when more than one instance of the compiling rewriter run at the same
    2751             : ///        time.
    2752             : /// \param unique A number that will be incorporated into the filename.
    2753             : /// \return A filename that should be used to store the generated C++ code in.
    2754             : ///
    2755           5 : static std::string generate_cpp_filename(std::size_t unique)
    2756             : {
    2757           5 :   const char* env_dir = std::getenv("MCRL2_COMPILEDIR");
    2758           5 :   std::ostringstream filename;
    2759           5 :   std::string filedir;
    2760           5 :   if (env_dir)
    2761             :   {
    2762           0 :     filedir = env_dir;
    2763           0 :     if (*filedir.rbegin() != '/')
    2764             :     {
    2765           0 :       filedir.append("/");
    2766             :     }
    2767             :   }
    2768             :   else
    2769             :   {
    2770           5 :     filedir = "./";
    2771             :   }
    2772           5 :   time_t now = time(nullptr);
    2773           5 :   struct tm tstruct = *localtime(&now);
    2774             : 
    2775             :   // The static_cast<std::size_t> is required, as the calculation does not fit into a 32 bit int, yielding a negative number. 
    2776           5 :   std::size_t unique_time = ((((static_cast<std::size_t>(tstruct.tm_year)*12+tstruct.tm_mon)*31+tstruct.tm_mday)*24+
    2777           5 :                                 tstruct.tm_hour)*60+tstruct.tm_min)*60 + tstruct.tm_sec;
    2778             :   // the name below must be unique. If two .cpp files have the same name, loading the second
    2779             :   // may effectively load the first. The pid of the current process and the this pointer in 
    2780             :   // unique could lead to duplicate filenames, as happened in September 2021. A time tag has
    2781             :   // been added to guarantee further uniqueness. 
    2782           5 :   filename << filedir << "jittyc_" << getpid() << "_" << (unique % 100000000) << "_" << unique_time << ".cpp";
    2783          10 :   return filename.str();
    2784           5 : }
    2785             : 
    2786             : ///
    2787             : /// \brief filter_function_symbols selects the function symbols from source for which filter
    2788             : ///        returns true, and copies them to dest.
    2789             : /// \param source The input list.
    2790             : /// \param dest The output list.
    2791             : /// \param filter A functor of type bool(const function_symbol&)
    2792             : ///
    2793             : template <class Filter>
    2794          10 : void filter_function_symbols(const function_symbol_vector& source, function_symbol_vector& dest, Filter filter)
    2795             : {
    2796         825 :   for (function_symbol_vector::const_iterator it = source.begin(); it != source.end(); ++it)
    2797             :   {
    2798         815 :     if (filter(*it))
    2799             :     {
    2800         440 :       dest.push_back(*it);
    2801             :     }
    2802             :   }
    2803          10 : }
    2804             : 
    2805           5 : void RewriterCompilingJitty::generate_code(const std::string& filename)
    2806             : {
    2807           5 :   std::ofstream cpp_file(filename);
    2808           5 :   std::stringstream rewr_code;
    2809             :   // arity_bound is one larger than the maximal arity. 
    2810           5 :   arity_bound = 1+std::max(calc_max_arity(m_data_specification_for_enumeration.constructors()),
    2811           5 :                            calc_max_arity(m_data_specification_for_enumeration.mappings()));
    2812             : 
    2813             :   // - Store all used function symbols in a vector
    2814           5 :   std::vector<function_symbol> function_symbols; 
    2815           5 :   filter_function_symbols(m_data_specification_for_enumeration.constructors(), function_symbols, data_equation_selector);
    2816           5 :   filter_function_symbols(m_data_specification_for_enumeration.mappings(), function_symbols, data_equation_selector);
    2817             : 
    2818             : 
    2819             :   // The rewrite functions are first stored in a separate buffer (rewrite_functions),
    2820             :   // because during the generation process, new function symbols are created. This
    2821             :   // affects the value that the macro INDEX_BOUND should have before loading
    2822             :   // jittycpreamble.h.
    2823           5 :   ImplementTree code_generator(*this, function_symbols);
    2824             : 
    2825           5 :   index_bound = atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::max_index() + 1;
    2826             : 
    2827           5 :   functions_when_arguments_are_not_in_normal_form = std::vector<rewriter_function>(arity_bound * index_bound);
    2828           5 :   functions_when_arguments_are_in_normal_form = std::vector<rewriter_function>(arity_bound * index_bound);
    2829             : 
    2830           5 :   cpp_file << "#define INDEX_BOUND__ " << index_bound << "// These values are not used anymore.\n"
    2831           5 :               "#define ARITY_BOUND__ " << arity_bound << "// These values are not used anymore.\n";
    2832           5 :   cpp_file << "#include \"mcrl2/data/detail/rewrite/jittycpreamble.h\"\n";
    2833             : 
    2834             :   cpp_file << "namespace {\n"
    2835             :                "// Anonymous namespace so the compiler uses internal linkage for the generated\n"
    2836             :                "// rewrite code.\n"
    2837             :                "\n"
    2838             :                "struct rewr_functions\n"
    2839             :                "{\n"
    2840             : 
    2841             :                "  // A rewrite_term is a term that may or may not be in normal form. If the method\n"
    2842             :                "  // normal_form is invoked, it will calculate a normal form for itself as efficiently as possible.\n"
    2843             :                "  template <class REWRITE_TERM>\n"
    2844             :                "  static data_expression& local_rewrite(const REWRITE_TERM& t)\n"
    2845             :                "  {\n"
    2846             :                "    return t.normal_form();\n"
    2847             :                "  }\n"
    2848             :                "\n"
    2849             :                "  // A rewrite_term is a term that may or may not be in normal form. If the method\n"
    2850             :                "  // normal_form is invoked, it will calculate a normal form for itself as efficiently as possible.\n"
    2851             :                "  template <class REWRITE_TERM>\n"
    2852             :                "  static void local_rewrite(data_expression& result,\n"
    2853             :                "                            const REWRITE_TERM& t) \n"
    2854             :                "  {\n"
    2855             :                "     t.normal_form(result);\n"
    2856             :                "  }\n"
    2857             :                "\n"
    2858             :                "  static const data_expression& local_rewrite(const data_expression& t)\n"
    2859             :                "  {\n"
    2860             :                "    return t;\n"
    2861             :                "  }\n"
    2862             :                "\n"
    2863             :                "  static void local_rewrite(data_expression& result, const data_expression& t)\n"
    2864             :                "  {\n"
    2865             :                "     result=t;\n"
    2866             :                "  }\n"
    2867           5 :                "\n";
    2868             : 
    2869             :   rewr_code << "  // We're declaring static members in a struct rather than simple functions in\n"
    2870           5 :                "  // the global scope, so that we don't have to worry about forward declarations.\n";
    2871           5 :   code_generator.generate_rewr_functions(rewr_code,m_data_specification_for_enumeration);
    2872             :   rewr_code << "};\n"
    2873           5 :                "} // namespace\n";
    2874             : 
    2875           5 :   code_generator.generate_delayed_application_functions(cpp_file);
    2876             : 
    2877           5 :   cpp_file << rewr_code.str();
    2878             : 
    2879             :   cpp_file << "void set_the_precompiled_rewrite_functions_in_a_lookup_table(RewriterCompilingJitty* this_rewriter)\n"
    2880           5 :               "{\n";
    2881           5 :   cpp_file << "  assert(&this_rewriter->functions_when_arguments_are_not_in_normal_form == (void *)" << &functions_when_arguments_are_not_in_normal_form << ");  // Check that this table matches the one rewriter is actually using.\n";
    2882           5 :   cpp_file << "  assert(&this_rewriter->functions_when_arguments_are_in_normal_form == (void *)" << &functions_when_arguments_are_in_normal_form << ");  // Check that this table matches the one rewriter is actually using.\n";
    2883             :   cpp_file << "  for(rewriter_function& f: this_rewriter->functions_when_arguments_are_not_in_normal_form)\n"
    2884             :            << "  {\n"
    2885             :            << "    f = nullptr;\n"
    2886           5 :            << "  }\n";
    2887             :   cpp_file << "  for(rewriter_function& f: this_rewriter->functions_when_arguments_are_in_normal_form)\n"
    2888             :            << "  {\n"
    2889             :            << "    f = nullptr;\n"
    2890           5 :            << "  }\n";
    2891             : 
    2892             :   // Fill tables with the rewrite functions
    2893           5 :   RewriterCompilingJitty::substitution_type sigma;
    2894           5 :   normal_forms_for_constants.clear();
    2895        1030 :   for (const rewr_function_spec& f: code_generator.implemented_rewrs())
    2896             :   {
    2897        1025 :     if (!f.delayed())
    2898             :     {
    2899         897 :       std::size_t index = atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::index(f.fs());
    2900         897 :       if (f.arity()>0)
    2901             :       {
    2902         457 :         cpp_file << "  this_rewriter->functions_when_arguments_are_not_in_normal_form[this_rewriter->arity_bound * "
    2903         457 :                  << index
    2904         457 :                  << " + " << f.arity() << "] = rewr_functions::"
    2905         457 :                  << f.name() << "_term;\n";
    2906         457 :         cpp_file << "  this_rewriter->functions_when_arguments_are_in_normal_form[this_rewriter->arity_bound * "
    2907         457 :                  << index
    2908         457 :                  << " + " << f.arity() << "] = rewr_functions::"
    2909         457 :                  << f.name() << "_term_arg_in_normal_form;\n";
    2910             :       }
    2911             :       else
    2912             :       { 
    2913         440 :         if (index>=normal_forms_for_constants.size())
    2914             :         {
    2915         440 :           normal_forms_for_constants.resize(index+1);
    2916             :         }
    2917         440 :         normal_forms_for_constants[index]=jitty_rewriter(f.fs(),sigma);
    2918             :       }
    2919             :     }
    2920             :   }
    2921             : 
    2922             : 
    2923           5 :   cpp_file << "}\n";
    2924           5 :   cpp_file.close();
    2925           5 : }
    2926             : 
    2927           5 : void RewriterCompilingJitty::BuildRewriteSystem()
    2928             : {
    2929           5 :   CleanupRewriteSystem();
    2930             : 
    2931             :   // Try to find out from environment which compile script to use.
    2932             :   // If not set, choose one of the following two:
    2933             :   // * if "mcrl2compilerewriter" is in the same directory as the executable,
    2934             :   //   this is the version we favour. This is especially needed for single
    2935             :   //   bundle applications on MacOSX. Furthermore, it is the more foolproof
    2936             :   //   approach on other platforms.
    2937             :   // * by default, fall back to the system provided mcrl2compilerewriter script.
    2938             :   //   in this case, we rely on the script being available in the user's
    2939             :   //   $PATH environment variable.
    2940           5 :   std::string compile_script;
    2941           5 :   const char* env_compile_script = std::getenv("MCRL2_COMPILEREWRITER");
    2942           5 :   if (env_compile_script != nullptr)
    2943             :   {
    2944           5 :     compile_script = env_compile_script;
    2945             :   }
    2946           0 :   else if(mcrl2::utilities::file_exists(mcrl2::utilities::get_executable_basename() + "/mcrl2compilerewriter"))
    2947             :   {
    2948           0 :     compile_script = mcrl2::utilities::get_executable_basename() + "/mcrl2compilerewriter";
    2949             :   }
    2950             :   else
    2951             :   {
    2952           0 :     compile_script = "mcrl2compilerewriter";
    2953             :   }
    2954             : 
    2955           5 :    rewriter_so = std::shared_ptr<uncompiled_library>(new uncompiled_library(compile_script));
    2956             : 
    2957           5 :   mCRL2log(verbose) << "using '" << compile_script << "' to compile rewriter." << std::endl;
    2958           5 :   stopwatch time;
    2959             : 
    2960           5 :   jittyc_eqns.clear();
    2961         933 :   for(std::set < data_equation >::const_iterator it = rewrite_rules.begin(); it != rewrite_rules.end(); ++it)
    2962             :   {
    2963         928 :     jittyc_eqns[down_cast<function_symbol>(get_nested_head(it->lhs()))].push_front(*it);
    2964             :   }
    2965             : 
    2966           5 :   std::string cpp_file = generate_cpp_filename(reinterpret_cast<std::size_t>(this));
    2967           5 :   generate_code(cpp_file);
    2968             : 
    2969           5 :   mCRL2log(verbose) << "generated " << cpp_file << " in " << time.time() << "ms, compiling..." << std::endl;
    2970           5 :   time.reset();
    2971             : 
    2972             :   try
    2973             :   {
    2974           5 :     rewriter_so->compile(cpp_file);
    2975             :   }
    2976           0 :   catch(std::runtime_error& e)
    2977             :   {
    2978           0 :     rewriter_so->leave_files();
    2979           0 :     throw mcrl2::runtime_error(std::string("Could not compile rewriter: ") + e.what());
    2980           0 :   }
    2981             : 
    2982           5 :   mCRL2log(verbose) << "compiled in " << time.time() << "ms, loading rewriter..." << std::endl;
    2983             : 
    2984             :   bool (*init)(rewriter_interface*, RewriterCompilingJitty* this_rewriter);
    2985           5 :   rewriter_interface interface = { mcrl2::utilities::get_toolset_version(), "Unknown error when loading rewriter.", this, nullptr, nullptr };
    2986             :   try
    2987             :   {
    2988             :     typedef bool rewrite_function_type(rewriter_interface*, RewriterCompilingJitty*);
    2989           5 :     init = reinterpret_cast<rewrite_function_type*>(rewriter_so->proc_address("init"));
    2990             :   }
    2991           0 :   catch(std::runtime_error& e)
    2992             :   {
    2993           0 :     rewriter_so->leave_files();
    2994             : #ifndef MCRL2_DISABLE_JITTYC_VERSION_CHECK
    2995           0 :     throw mcrl2::runtime_error(std::string("Could not load rewriter: ") + e.what());
    2996             : #endif
    2997           0 :   }
    2998             : 
    2999             : #ifdef NDEBUG // In non debug mode clear compiled files directly after loading.
    3000             :   if (logger::get_reporting_level()<debug)  // leave the files in debug mode. 
    3001             :   {
    3002             :     try
    3003             :     {
    3004             :       rewriter_so->cleanup();
    3005             :     }
    3006             :     catch (std::runtime_error& error)
    3007             :     {
    3008             :       mCRL2log(mcrl2::log::error) << "Could not cleanup temporary files: " << error.what() << std::endl;
    3009             :     }
    3010             :   }
    3011             : #endif
    3012             : 
    3013           5 :   if (!init(&interface,this))
    3014             :   {
    3015             : #ifndef MCRL2_DISABLE_JITTYC_VERSION_CHECK
    3016           0 :     throw mcrl2::runtime_error(std::string("Could not load rewriter: ") + interface.status);
    3017             : #endif
    3018             :   }
    3019           5 :   so_rewr_cleanup = interface.rewrite_cleanup;
    3020           5 :   so_rewr = interface.rewrite_external;
    3021             : 
    3022           5 :   mCRL2log(verbose) << interface.status << std::endl;
    3023           5 : }
    3024             : 
    3025           5 : RewriterCompilingJitty::RewriterCompilingJitty(
    3026             :                           const data_specification& data_spec,
    3027           5 :                           const used_data_equation_selector& equation_selector)
    3028             :   : Rewriter(data_spec,equation_selector),
    3029           5 :     jitty_rewriter(data_spec,equation_selector),
    3030          10 :     m_nf_cache(new normal_form_cache())
    3031             : {
    3032           5 :   thread_initialise();
    3033           5 :   assert(m_nf_cache->empty());
    3034           5 :   so_rewr_cleanup = nullptr;
    3035           5 :   so_rewr = nullptr;
    3036           5 :   rewriting_in_progress = false;
    3037             : 
    3038           5 :   made_files = false;
    3039           5 :   rewrite_rules.clear();
    3040             : 
    3041        1652 :   for (const data_equation& e: data_spec.equations())
    3042             :   {
    3043        1647 :     if (data_equation_selector(e))
    3044             :     {
    3045         928 :       const data_equation rule=e;
    3046             :       try
    3047             :       {
    3048         928 :         CheckRewriteRule(rule);
    3049         928 :         if (rewrite_rules.insert(rule).second)
    3050             :         {
    3051             :           // The equation has been added as a rewrite rule, otherwise the equation was already present.
    3052             :           // data_equation_selector.add_function_symbols(rule.lhs());
    3053             :         }
    3054             :       }
    3055           0 :       catch (std::runtime_error& error)
    3056             :       {
    3057           0 :         mCRL2log(warning) << error.what() << std::endl;
    3058           0 :       }
    3059         928 :     }
    3060             :   }
    3061             : 
    3062           5 :   BuildRewriteSystem();
    3063           5 : }
    3064             : 
    3065          15 : RewriterCompilingJitty::~RewriterCompilingJitty()
    3066             : {
    3067           5 :   CleanupRewriteSystem();
    3068          10 : }
    3069             : 
    3070        6175 : void RewriterCompilingJitty::rewrite(
    3071             :      data_expression& result,
    3072             :      const data_expression& term,
    3073             :      substitution_type& sigma)
    3074             : {
    3075             : #ifdef MCRL2_DISPLAY_REWRITE_STATISTICS
    3076             :   data::detail::increment_rewrite_count();
    3077             : #endif
    3078             :   // Save global sigma and restore it afterwards, as rewriting might be recursive with different
    3079             :   // substitutions, due to the enumerator.
    3080             : // std::cerr << "REWRITE " << term << "\n";
    3081        6175 :   substitution_type *saved_sigma=global_sigma;
    3082        6175 :   global_sigma=&sigma;
    3083        6175 :   if (rewriting_in_progress)
    3084             :   {
    3085           0 :     so_rewr(result,term, this);
    3086             :   }
    3087             :   else
    3088             :   {
    3089        6175 :     rewriting_in_progress=true;
    3090             :     try
    3091             :     {
    3092        6175 :       so_rewr(result,term, this);
    3093             :     }
    3094           0 :     catch (recalculate_term_as_stack_is_too_small&)
    3095             :     {
    3096           0 :       assert(!atermpp::detail::g_thread_term_pool().is_shared_locked()); 
    3097           0 :       rewriting_in_progress=false; // Restart rewriting, due to a stack overflow.
    3098             :                                    // The stack is a vector, and it may be relocated in memory when
    3099             :                                    // resized. References to the stack loose their validity. 
    3100           0 :       m_rewrite_stack.reserve_more_space();
    3101           0 :       rewrite(result,term,sigma);
    3102             : // std::cerr << "REWRITE " << term << " --> " << result << "\n";
    3103           0 :       return;
    3104           0 :     }
    3105        6175 :     rewriting_in_progress=false;
    3106        6175 :     assert(m_rewrite_stack.stack_size()==0);
    3107             :   }
    3108             : 
    3109        6175 :   global_sigma=saved_sigma;
    3110             : // std::cerr << "REWRITE " << term << " --> " << result << "\n";
    3111        6175 :   return;
    3112             : }
    3113             : 
    3114           0 : data_expression RewriterCompilingJitty::rewrite(
    3115             :      const data_expression& term,
    3116             :      substitution_type& sigma)
    3117             : {
    3118             : // std::cerr << "REWRITE " << term << "\n";
    3119           0 :   data_expression result;
    3120           0 :   rewrite(result, term, sigma);
    3121             : // std::cerr << "REWRITE " << term << " --> " << result << "\n";
    3122           0 :   return result;
    3123           0 : }
    3124             : 
    3125           0 : rewrite_strategy RewriterCompilingJitty::getStrategy()
    3126             : {
    3127           0 :   return jitty_compiling;
    3128             : }
    3129             : 
    3130             : }
    3131             : }
    3132             : }
    3133             : 
    3134             : #endif

Generated by: LCOV version 1.14