LCOV - code coverage report
Current view: top level - data/include/mcrl2/data/experimental - type_check_tree.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 568 663 85.7 %
Date: 2024-04-21 03:44:01 Functions: 110 117 94.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink
       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 mcrl2/data/experimental/type_check_tree.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_DATA_EXPERIMENTAL_TYPE_CHECK_TREE_H
      13             : #define MCRL2_DATA_EXPERIMENTAL_TYPE_CHECK_TREE_H
      14             : 
      15             : #include "mcrl2/data/parse.h"
      16             : #include "mcrl2/data/replace.h"
      17             : #include "mcrl2/data/experimental/type_checker.h"
      18             : 
      19             : namespace mcrl2 {
      20             : 
      21             : namespace data {
      22             : 
      23             : typedef std::map<untyped_sort_variable, sort_expression> sort_substitution;
      24             : typedef std::pair<sort_substitution, int> solution; // the second element is the cost of the solution
      25             : 
      26             : template <typename T>
      27         361 : bool has_untyped_sort(const T& x)
      28             : {
      29         361 :   return data::search_sort_expression(x, untyped_sort());
      30             : }
      31             : 
      32             : template <typename T>
      33         160 : T replace_untyped_sort(const T& x, const sort_expression& replacement)
      34             : {
      35        1042 :   return data::replace_sort_expressions(x, [&replacement](const sort_expression& x) { return is_untyped_sort(x) ? replacement : x; }, true);
      36             : }
      37             : 
      38             : inline
      39        1328 : const untyped_sort_variable& make_untyped_sort_variable(const sort_expression& x)
      40             : {
      41        1328 :   return atermpp::down_cast<untyped_sort_variable>(x);
      42             : }
      43             : 
      44           0 : inline sort_expression substitute(const sort_expression& x, const sort_substitution& sigma)
      45             : {
      46           0 :   if (is_untyped_sort_variable(x))
      47             :   {
      48           0 :     const untyped_sort_variable& v = make_untyped_sort_variable(x);
      49           0 :     auto i = sigma.find(v);
      50           0 :     if (i != sigma.end())
      51             :     {
      52           0 :       return i->second;
      53             :     }
      54             :   }
      55           0 :   return x;
      56             : }
      57             : 
      58             : template <typename Container>
      59         482 : std::string print_node_vector(const std::string& name, const Container& nodes, const std::string& sep = ", ", const std::string& first = "", const std::string& last = "")
      60             : {
      61         482 :   std::vector<std::string> s;
      62        2062 :   for (auto i = nodes.begin(); i != nodes.end(); ++i)
      63             :   {
      64        1580 :     s.push_back((*i)->print());
      65             :   }
      66         482 :   std::ostringstream out;
      67         482 :   out << name << "(" << first;
      68         482 :   out << utilities::string_join(s, sep);
      69         482 :   out << last << ")";
      70         964 :   return out.str();
      71         482 : }
      72             : 
      73             : template <typename Container>
      74             : std::string print_vector(const std::string& name, const Container& nodes)
      75             : {
      76             :   std::ostringstream out;
      77             :   out << name << "(";
      78             :   for (auto i = nodes.begin(); i != nodes.end(); ++i)
      79             :   {
      80             :     if (i != nodes.begin())
      81             :     {
      82             :       out << ", ";
      83             :     }
      84             :     out << *i;
      85             :   }
      86             :   out << ")";
      87             :   return out.str();
      88             : }
      89             : 
      90             : struct type_check_node;
      91             : 
      92             : typedef std::shared_ptr<type_check_node> type_check_node_ptr;
      93             : 
      94             : struct type_check_context
      95             : {
      96             :   std::map<core::identifier_string, sort_expression_list> system_constants;
      97             :   std::map<core::identifier_string, function_sort_list> system_functions;
      98             :   std::map<core::identifier_string, sort_expression> user_constants;
      99             :   std::map<core::identifier_string, function_sort_list> user_functions;
     100             :   std::map<core::identifier_string, std::vector<sort_expression> > declared_variables;
     101             :   mutable std::size_t sort_variable_index;
     102             : 
     103          71 :   type_check_context(const data::data_specification& dataspec = data::data_specification())
     104          71 :     : sort_variable_index(0)
     105             :   {
     106          71 :     type_checker checker(dataspec);
     107          71 :     system_constants = checker.system_constants();
     108          71 :     system_functions = checker.system_functions();
     109          71 :     user_constants = checker.user_constants();
     110          71 :     user_functions = checker.user_functions();
     111          71 :   }
     112             : 
     113             :   // Returns the system defined constants and the user defined constants matching with name
     114             :   std::pair<sort_expression_list, sort_expression_list> find_matching_constants(const std::string& name) const;
     115             : 
     116             :   // Returns the system defined functions and the user defined functions matching with (name, arity)
     117             :   // N.B. Untyped sorts are replaced with fresh sort variables.
     118             :   std::pair<function_sort_list, function_sort_list> find_matching_functions(const std::string& name, std::size_t arity) const;
     119             : 
     120             :   // Returns the system defined functions and the user defined functions matching with name
     121             :   // N.B. Untyped sorts are replaced with fresh sort variables.
     122             :   std::pair<function_sort_list, function_sort_list> find_matching_functions(const std::string& name) const;
     123             : 
     124             :   // Returns the variables matching with name
     125             :   std::vector<sort_expression> find_matching_variables(const std::string& name) const;
     126             : 
     127         512 :   untyped_sort_variable create_sort_variable() const
     128             :   {
     129         512 :     return untyped_sort_variable(sort_variable_index++);
     130             :   }
     131             : 
     132          75 :   void add_context_variable(const variable& v)
     133             :   {
     134          75 :     declared_variables[v.name()].push_back(v.sort());
     135          75 :   }
     136             : 
     137          96 :   void add_context_variables(const variable_list& variables)
     138             :   {
     139         169 :     for (const variable& v: variables)
     140             :     {
     141          73 :       add_context_variable(v);
     142             :     }
     143          96 :   }
     144             : 
     145          75 :   void remove_context_variable(const variable& v)
     146             :   {
     147          75 :     auto i = declared_variables.find(v.name());
     148          75 :     if (i->second.size() <= 1)
     149             :     {
     150          59 :       declared_variables.erase(i);
     151             :     }
     152             :     else
     153             :     {
     154          16 :       i->second.pop_back();
     155             :     }
     156          75 :   }
     157             : 
     158          96 :   void remove_context_variables(const variable_list& variables)
     159             :   {
     160         169 :     for (const variable& v: variables) // N.B. the order of insertion and removal should not matter
     161             :     {
     162          73 :       remove_context_variable(v);
     163             :     }
     164          96 :   }
     165             : 
     166             : protected:
     167             :   // replace occurrences of untyped sort in sorts by fresh sort variables
     168         148 :   function_sort_list replace_untyped_sorts(const function_sort_list& sorts) const
     169             :   {
     170         148 :     std::vector<function_sort> result;
     171         507 :     for (const function_sort& f: sorts)
     172             :     {
     173         359 :       if (has_untyped_sort(f))
     174             :       {
     175         159 :         function_sort f1 = replace_untyped_sort(f, create_sort_variable());
     176         159 :         result.push_back(f1);
     177         159 :       }
     178             :       else
     179             :       {
     180         200 :         result.push_back(f);
     181             :       }
     182             :     }
     183         296 :     return function_sort_list(result.begin(), result.end());
     184         148 :   }
     185             : };
     186             : 
     187             : struct type_check_constraint;
     188             : typedef std::shared_ptr<type_check_constraint> constraint_ptr;
     189             : constraint_ptr substitute_constraint(constraint_ptr p, const sort_substitution& sigma);
     190             : 
     191             : struct type_check_constraint
     192             : {
     193             :   int cost;
     194             : 
     195        2184 :   type_check_constraint(int cost_ = 0)
     196        2184 :     : cost(cost_)
     197        2184 :   {}
     198             : 
     199             :   virtual std::string print() const = 0;
     200             : };
     201             : 
     202             : constraint_ptr make_and_constraint(const std::vector<constraint_ptr>& alternatives);
     203             : constraint_ptr make_or_constraint(const std::vector<constraint_ptr>& alternatives);
     204             : constraint_ptr make_is_equal_to_constraint(const sort_expression& s1, const sort_expression& s2, int cost = 0);
     205             : 
     206             : struct true_constraint final: public type_check_constraint
     207             : {
     208         353 :   true_constraint(int cost = 0)
     209         353 :     : type_check_constraint(cost)
     210         353 :   {}
     211             : 
     212          34 :   std::string print() const override
     213             :   {
     214          34 :     return "true";
     215             :   }
     216             : };
     217             : 
     218             : struct false_constraint final: public type_check_constraint
     219             : {
     220             :   std::string message;
     221             : 
     222           2 :   false_constraint(const std::string& message_)
     223           2 :     : message(message_)
     224           2 :   {}
     225             : 
     226           2 :   std::string print() const override
     227             :   {
     228           4 :     return "false(" + message + ")";
     229             :   }
     230             : };
     231             : 
     232             : inline
     233           2 : constraint_ptr make_false_constraint(const std::string& message)
     234             : {
     235           2 :   return constraint_ptr(new false_constraint(message));
     236             : }
     237             : 
     238             : inline
     239         353 : constraint_ptr make_true_constraint(int cost = 0)
     240             : {
     241         353 :   return constraint_ptr(new true_constraint(cost));
     242             : }
     243             : 
     244             : // The sort of the corresponding data expression should be equal to 'sort'.
     245             : struct is_element_of_constraint final: public type_check_constraint
     246             : {
     247             :   untyped_sort_variable s;
     248             :   std::vector<sort_expression> sorts;
     249             : 
     250        1328 :   is_element_of_constraint(const untyped_sort_variable& s_, const std::vector<sort_expression>& sorts_, int cost = 0)
     251        1328 :     : type_check_constraint(cost), s(s_), sorts(sorts_)
     252        1328 :   {}
     253             : 
     254        1236 :   std::string print() const override
     255             :   {
     256        1236 :     if (sorts.size() == 1)
     257             :     {
     258        1492 :       return data::pp(s) + " = " + data::pp(*sorts.begin());
     259             :     }
     260         980 :     return data::pp(s) + " in " + core::detail::print_set(sorts);
     261             :   }
     262             : };
     263             : 
     264             : inline
     265           0 : constraint_ptr make_function_sort_constraint(const function_sort& f1, const sort_expression& s2)
     266             : {
     267           0 :   auto const& domain1 = f1.domain();
     268           0 :   if (!is_function_sort(s2))
     269             :   {
     270           0 :     throw mcrl2::runtime_error("could not make function sort constraint");
     271             :   }
     272           0 :   const function_sort& f2 = atermpp::down_cast<function_sort>(s2);
     273           0 :   auto const& domain2 = f2.domain();
     274           0 :   if (domain1.size() != domain1.size())
     275             :   {
     276           0 :     return make_false_constraint("function sorts do not match");
     277             :   }
     278           0 :   std::vector<constraint_ptr> alternatives;
     279           0 :   alternatives.push_back(make_is_equal_to_constraint(f1.codomain(), f2.codomain()));
     280           0 :   auto i1 = domain1.begin();
     281           0 :   auto i2 = domain2.begin();
     282           0 :   for (; i1 != domain1.end(); ++i1, ++i2)
     283             :   {
     284           0 :     alternatives.push_back(make_is_equal_to_constraint(*i1, *i2));
     285             :   }
     286           0 :   return make_and_constraint(alternatives);
     287           0 : }
     288             : 
     289             : inline
     290        1328 : constraint_ptr make_is_element_of_constraint(const sort_expression& s, const std::vector<sort_expression>& sorts, int cost = 0)
     291             : {
     292             :   // optimizations
     293        1328 :   if (is_untyped_sort(s))
     294             :   {
     295           0 :     return make_true_constraint();
     296             :   }
     297        1328 :   if (std::find(sorts.begin(), sorts.end(), untyped_sort()) != sorts.end())
     298             :   {
     299           0 :     return make_true_constraint();
     300             :   }
     301        1328 :   if (is_function_sort(s))
     302             :   {
     303           0 :     const function_sort& f1 = atermpp::down_cast<function_sort>(s);
     304           0 :     std::vector<constraint_ptr> alternatives;
     305           0 :     for (const sort_expression& s2: sorts)
     306             :     {
     307           0 :       alternatives.push_back(make_function_sort_constraint(f1, s2));
     308             :     }
     309           0 :     return make_and_constraint(alternatives);
     310           0 :   }
     311        1328 :   if (std::find(sorts.begin(), sorts.end(), s) != sorts.end())
     312             :   {
     313           0 :     return make_true_constraint();
     314             :   }
     315        1328 :   return constraint_ptr(new is_element_of_constraint(make_untyped_sort_variable(s), sorts, cost));
     316             : }
     317             : 
     318             : // The sort of the corresponding data expression should be equal to 'sort'.
     319             : struct is_equal_to_constraint final: public type_check_constraint
     320             : {
     321             :   untyped_sort_variable s1;
     322             :   sort_expression s2;
     323             : 
     324             :   is_equal_to_constraint(const untyped_sort_variable& s1_, const sort_expression& s2_, int cost = 0)
     325             :     : type_check_constraint(cost), s1(s1_), s2(s2_)
     326             :   {}
     327             : 
     328             :   std::string print() const override
     329             :   {
     330             :     return "is_equal_to(" + data::pp(s1) + ", " + data::pp(s2) + ")";
     331             :   }
     332             : };
     333             : 
     334             : inline
     335         771 : constraint_ptr make_is_equal_to_constraint(const sort_expression& s1,
     336             :                                      const sort_expression& s2, int /* cost */)
     337             : {
     338         771 :   if (s1 == s2)
     339             :   {
     340          25 :     return make_true_constraint();
     341             :   }
     342         746 :   if (is_untyped_sort(s1) || is_untyped_sort(s2))
     343             :   {
     344           0 :     return make_true_constraint();
     345             :   }
     346         746 :   if (is_untyped_sort_variable(s1))
     347             :   {
     348        1142 :     return make_is_element_of_constraint(s1, { s2 });
     349             :   }
     350         175 :   if (is_untyped_sort_variable(s2))
     351             :   {
     352         350 :     return make_is_element_of_constraint(s2, { s1 });
     353             :     // return constraint_ptr(new is_equal_to_constraint(make_untyped_sort_variable(s2), s1, cost));
     354             :   }
     355           0 :   throw mcrl2::runtime_error("cannot make is_equal_to constraint");
     356             : }
     357             : 
     358             : // The sort variable s1 should be a subsort of s2.
     359             : struct subsort_constraint final: public type_check_constraint
     360             : {
     361             :   sort_expression s1;
     362             :   sort_expression s2;
     363             : 
     364          75 :   subsort_constraint(const sort_expression& s1_, const sort_expression& s2_, int cost = 0)
     365          75 :     : type_check_constraint(cost), s1(s1_), s2(s2_)
     366          75 :   {}
     367             : 
     368          75 :   std::string print() const override
     369             :   {
     370         150 :     return "subsort(" + data::pp(s1) + ", " + data::pp(s2) + ")";
     371             :   }
     372             : };
     373             : 
     374             : inline
     375        1174 : constraint_ptr make_subsort_constraint(const sort_expression& s1, const sort_expression& s2, int cost = 0)
     376             : {
     377             :   // optimizations
     378        1174 :   if (sort_bool::is_bool(s1) || sort_bool::is_bool(s2))
     379             :   {
     380          48 :     return make_is_equal_to_constraint(s1, s2, cost);
     381             :   }
     382        1126 :   if (is_untyped_sort(s1) || is_untyped_sort(s2))
     383             :   {
     384           0 :     return make_true_constraint(cost);
     385             :   }
     386        1126 :   if (is_container_sort(s1) && is_container_sort(s2))
     387             :   {
     388           0 :     const container_sort& c1 = atermpp::down_cast<container_sort>(s1);
     389           0 :     const container_sort& c2 = atermpp::down_cast<container_sort>(s2);
     390           0 :     if (c1.container_name() == c2.container_name())
     391             :     {
     392           0 :       return make_subsort_constraint(c1.element_sort(), c2.element_sort());
     393             :     }
     394             :     else
     395             :     {
     396           0 :       return make_false_constraint("incompatible container sorts");
     397             :     }
     398             :   }
     399        1126 :   if (is_container_sort(s1) && is_untyped_sort_variable(s2))
     400             :   {
     401         134 :     return make_is_equal_to_constraint(s1, s2);
     402             :   }
     403         992 :   if (is_untyped_sort_variable(s1) && is_container_sort(s2))
     404             :   {
     405         271 :     return make_is_equal_to_constraint(s1, s2);
     406             :   }
     407         721 :   if (is_function_sort(s1) && is_function_sort(s2))
     408             :   {
     409           0 :     const function_sort& f1 = atermpp::down_cast<function_sort>(s1);
     410           0 :     const function_sort& f2 = atermpp::down_cast<function_sort>(s2);
     411           0 :     auto const& domain1 = f1.domain();
     412           0 :     auto const& domain2 = f2.domain();
     413             : 
     414           0 :     if (domain1.size() != domain1.size())
     415             :     {
     416           0 :       return make_false_constraint("function sorts do not match");
     417             :     }
     418             : 
     419           0 :     std::vector<constraint_ptr> alternatives;
     420           0 :     alternatives.push_back(make_subsort_constraint(f1.codomain(), f2.codomain()));
     421           0 :     auto i1 = domain1.begin();
     422           0 :     auto i2 = domain2.begin();
     423           0 :     for (; i1 != domain1.end(); ++i1, ++i2)
     424             :     {
     425           0 :       alternatives.push_back(make_subsort_constraint(*i2, *i1));
     426             :     }
     427           0 :     return make_and_constraint(alternatives);
     428           0 :   }
     429         721 :   if (sort_pos::is_pos(s1))
     430             :   {
     431         705 :     return make_is_element_of_constraint(s2, { sort_pos::pos(), sort_nat::nat(), sort_int::int_(), sort_real::real_() });
     432             :   }
     433         580 :   if (sort_nat::is_nat(s1))
     434             :   {
     435         228 :     return make_is_element_of_constraint(s2, { sort_nat::nat(), sort_int::int_(), sort_real::real_() });
     436             :   }
     437         523 :   if (sort_int::is_int(s1))
     438             :   {
     439         126 :     return make_is_element_of_constraint(s2, { sort_int::int_(), sort_real::real_() });
     440             :   }
     441         481 :   if (sort_real::is_real(s1))
     442             :   {
     443          34 :     return make_is_equal_to_constraint(s2, sort_real::real_());
     444             :   }
     445         447 :   if (sort_pos::is_pos(s2))
     446             :   {
     447         122 :     return make_is_equal_to_constraint(s1, sort_pos::pos());
     448             :   }
     449         325 :   if (sort_nat::is_nat(s2))
     450             :   {
     451         363 :     return make_is_element_of_constraint(s1, { sort_pos::pos(), sort_nat::nat() });
     452             :   }
     453         204 :   if (sort_int::is_int(s2))
     454             :   {
     455         260 :     return make_is_element_of_constraint(s1, { sort_pos::pos(), sort_nat::nat(), sort_int::int_() });
     456             :   }
     457         139 :   if (sort_real::is_real(s2))
     458             :   {
     459         320 :     return make_is_element_of_constraint(s1, { sort_pos::pos(), sort_nat::nat(), sort_int::int_(), sort_real::real_() });
     460             :   }
     461             : 
     462          75 :   return constraint_ptr(new subsort_constraint(s1, s2, cost));
     463             : }
     464             : 
     465             : // joins disjunctions of is_element_of constraints
     466             : inline
     467         162 : std::vector<constraint_ptr> join_or_is_element_of_constraints(const std::vector<constraint_ptr>& constraints)
     468             : {
     469         162 :   std::vector<constraint_ptr> result;
     470         162 :   std::map<untyped_sort_variable, std::set<sort_expression> > is_element_of_constraints;
     471             : 
     472         616 :   for (const constraint_ptr& p: constraints)
     473             :   {
     474         454 :     is_element_of_constraint* x_is_element_of = dynamic_cast<is_element_of_constraint*>(p.get());
     475         454 :     if (x_is_element_of)
     476             :     {
     477          92 :       is_element_of_constraints[x_is_element_of->s].insert(x_is_element_of->sorts.begin(), x_is_element_of->sorts.end());
     478             :     }
     479             :     else
     480             :     {
     481         362 :       result.push_back(p);
     482             :     }
     483             :   }
     484         254 :   for (const auto& i: is_element_of_constraints)
     485             :   {
     486          92 :     result.push_back(make_is_element_of_constraint(i.first, std::vector<sort_expression>(i.second.begin(), i.second.end())));
     487             :   }
     488         324 :   return result;
     489         162 : }
     490             : 
     491             : struct or_constraint final: public type_check_constraint
     492             : {
     493             :   std::vector<constraint_ptr> alternatives;
     494             : 
     495          44 :   or_constraint(const std::vector<constraint_ptr>& alternatives_)
     496          44 :     : alternatives(alternatives_)
     497          44 :   {}
     498             : 
     499          44 :   std::string print() const
     500             :   {
     501          44 :     return print_node_vector("or", alternatives, "\n  ", "\n  ", "\n  ");
     502             :   }
     503             : };
     504             : 
     505             : inline
     506         162 : constraint_ptr make_or_constraint(const std::vector<constraint_ptr>& alternatives)
     507             : {
     508         162 :   std::vector<constraint_ptr> v;
     509         616 :   for (const constraint_ptr& p: alternatives)
     510             :   {
     511         454 :     true_constraint* x_no = dynamic_cast<true_constraint*>(p.get());
     512         454 :     if (x_no)
     513             :     {
     514           0 :       continue;
     515             :     }
     516         454 :     false_constraint* x_false = dynamic_cast<false_constraint*>(p.get());
     517         454 :     if (x_false)
     518             :     {
     519           0 :       continue;
     520             :     }
     521         454 :     or_constraint* x_or = dynamic_cast<or_constraint*>(p.get());
     522         454 :     if (x_or)
     523             :     {
     524           0 :       v.insert(v.end(), x_or->alternatives.begin(), x_or->alternatives.end());
     525           0 :       continue;
     526             :     }
     527         454 :     v.push_back(p);
     528             :   }
     529         162 :   v = join_or_is_element_of_constraints(v);
     530         162 :   if (v.size() == 0)
     531             :   {
     532           0 :     return constraint_ptr(new true_constraint());
     533             :   }
     534         162 :   if (v.size() == 1)
     535             :   {
     536         118 :     return v.front();
     537             :   }
     538          44 :   return constraint_ptr(new or_constraint(v));
     539         162 : }
     540             : 
     541             : struct and_constraint final: public type_check_constraint
     542             : {
     543             :   std::vector<constraint_ptr> alternatives;
     544             : 
     545         382 :   and_constraint(const std::vector<constraint_ptr>& alternatives_)
     546         382 :     : alternatives(alternatives_)
     547         382 :   {}
     548             : 
     549         382 :   std::string print() const override
     550             :   {
     551         382 :     return print_node_vector("and", alternatives);
     552             :   }
     553             : };
     554             : 
     555             : inline
     556         397 : constraint_ptr make_and_constraint(const std::vector<constraint_ptr>& alternatives)
     557             : {
     558         397 :   std::vector<constraint_ptr> v;
     559        1553 :   for (constraint_ptr p: alternatives)
     560             :   {
     561        1156 :     false_constraint* x_false = dynamic_cast<false_constraint*>(p.get());
     562        1156 :     if (x_false)
     563             :     {
     564           0 :       return p;
     565             :     }
     566        1156 :     true_constraint* x_no = dynamic_cast<true_constraint*>(p.get());
     567        1156 :     if (x_no)
     568             :     {
     569          25 :       continue;
     570             :     }
     571        1131 :     and_constraint* x_and = dynamic_cast<and_constraint*>(p.get());
     572        1131 :     if (x_and)
     573             :     {
     574           0 :       v.insert(v.end(), x_and->alternatives.begin(), x_and->alternatives.end());
     575           0 :       continue;
     576             :     }
     577        1131 :     v.push_back(p);
     578        1156 :   }
     579         397 :   if (v.size() == 0)
     580             :   {
     581           0 :     return make_true_constraint();
     582             :   }
     583         397 :   if (v.size() == 1)
     584             :   {
     585          15 :     return v.front();
     586             :   }
     587         382 :   return constraint_ptr(new and_constraint(v));
     588         397 : }
     589             : 
     590             : struct type_check_node
     591             : {
     592             :   type_check_context& context;
     593             :   std::vector<type_check_node_ptr> children;
     594             :   constraint_ptr constraint;
     595             :   untyped_sort_variable sort;
     596             : 
     597         321 :   type_check_node(type_check_context& context_, const std::vector<type_check_node_ptr>& children_)
     598         321 :     : context(context_), children(children_), constraint(make_true_constraint())
     599             :   {
     600         321 :     sort = context.create_sort_variable();
     601         321 :   }
     602             : 
     603         321 :   virtual ~type_check_node() {};
     604             : 
     605             :   // Adds a value to the 'sort' attribute
     606             :   // Sets the constraints that apply to this node to 'constraint'
     607           4 :   virtual void set_constraint(type_check_context& /* context */)
     608           4 :   {}
     609             : 
     610           0 :   virtual void apply_substitution(const sort_substitution& sigma)
     611             :   {
     612           0 :     for (const type_check_node_ptr& child: children)
     613             :     {
     614           0 :       child->apply_substitution(sigma);
     615             :     }
     616           0 :     constraint = substitute_constraint(constraint, sigma);
     617           0 :   }
     618             : 
     619         131 :   void set_children_constraints(type_check_context& context)
     620             :   {
     621         358 :     for (const type_check_node_ptr& child: children)
     622             :     {
     623         227 :       child->set_constraint(context);
     624             :     }
     625         131 :   }
     626             : 
     627             :   // Throws an exception if the node violates a well typedness rule
     628           0 :   virtual void check_well_typedness(const type_check_context& /* context */)
     629           0 :   {}
     630             : 
     631             :   virtual std::string print() const = 0;
     632             : };
     633             : 
     634             : struct id_node final: public type_check_node
     635             : {
     636             :   std::string value;
     637             : 
     638          84 :   id_node(type_check_context& context, const std::string& value_)
     639          84 :     : type_check_node(context, {}), value(value_)
     640          84 :   {}
     641             : 
     642          80 :   void set_constraint(type_check_context& context) override
     643             :   {
     644          80 :     std::vector<constraint_ptr> alternatives;
     645             : 
     646             :     // it is a variable
     647          80 :     std::vector<sort_expression> variable_sorts = context.find_matching_variables(value);
     648          80 :     if (variable_sorts.size() == 1)
     649             :     {
     650          77 :       alternatives.push_back(make_is_equal_to_constraint(sort, variable_sorts.front()));
     651             :     }
     652             : 
     653             :     // it is a constant
     654          80 :     std::pair<sort_expression_list, sort_expression_list> p = context.find_matching_constants(value);
     655          80 :     for (const sort_expression& s: p.first + p.second)
     656             :     {
     657           0 :       alternatives.push_back(make_is_equal_to_constraint(sort, s));
     658          80 :     }
     659             : 
     660             :     // it is a function
     661          80 :     std::pair<function_sort_list, function_sort_list> q = context.find_matching_functions(value);
     662          81 :     for (const function_sort& s: q.first + q.second)
     663             :     {
     664           1 :       alternatives.push_back(make_is_equal_to_constraint(sort, s));
     665          80 :     }
     666             : 
     667          80 :     if (alternatives.empty())
     668             :     {
     669           2 :       constraint = make_false_constraint("The id " + value + " is not declared!");
     670             :     }
     671             :     else
     672             :     {
     673          78 :       constraint = make_or_constraint(alternatives);
     674             :     }
     675          80 :   }
     676             : 
     677         250 :   std::string print() const override
     678             :   {
     679         500 :     return "id(" + value + ")";
     680             :   }
     681             : };
     682             : 
     683             : struct number_node final: public type_check_node
     684             : {
     685             :   std::string value;
     686             : 
     687          74 :   number_node(type_check_context& context, const std::string& value_)
     688          74 :     : type_check_node(context, {}), value(value_)
     689          74 :   {}
     690             : 
     691          70 :   void set_constraint(type_check_context& /* context */) override
     692             :   {
     693          70 :     if (detail::is_pos(value))
     694             :     {
     695          55 :       constraint = make_subsort_constraint(sort_pos::pos(), sort);
     696             :     }
     697          15 :     else if (detail::is_nat(value))
     698             :     {
     699          15 :       constraint = make_subsort_constraint(sort_nat::nat(), sort);
     700             :     }
     701             :     else
     702             :     {
     703           0 :       throw mcrl2::runtime_error("unknown numeric string " + value);
     704             :     }
     705          70 :   }
     706             : 
     707         184 :   std::string print() const override
     708             :   {
     709         368 :     return "number(" + value + ")";
     710             :   }
     711             : };
     712             : 
     713             : struct constant_node: public type_check_node
     714             : {
     715             :   std::string name;
     716             : 
     717          35 :   constant_node(type_check_context& context, const std::string& name_)
     718          35 :     : type_check_node(context, {}), name(name_)
     719          35 :   {}
     720             : 
     721          35 :   virtual ~constant_node() {}
     722             : 
     723          14 :   void set_constraint(type_check_context& context) override
     724             :   {
     725          14 :     std::pair<sort_expression_list, sort_expression_list> p = context.find_matching_constants(name);
     726          14 :     std::vector<constraint_ptr> alternatives;
     727          28 :     for (const sort_expression& s: p.first + p.second)
     728             :     {
     729          14 :       alternatives.push_back(make_subsort_constraint(s, sort));
     730          14 :     }
     731          14 :     constraint = make_or_constraint(alternatives);
     732          14 :     set_children_constraints(context);
     733          14 :   }
     734             : 
     735          70 :   std::string print() const override
     736             :   {
     737         140 :     return "constant(" + name + ")";
     738             :   }
     739             : };
     740             : 
     741             : struct true_node final: public constant_node
     742             : {
     743          12 :   true_node(type_check_context& context)
     744          12 :     : constant_node(context, "true")
     745          12 :   { }
     746             : };
     747             : 
     748             : struct false_node final: public constant_node
     749             : {
     750          10 :   false_node(type_check_context& context)
     751          10 :     : constant_node(context, "false")
     752          10 :   { }
     753             : };
     754             : 
     755             : struct empty_list_node final: public constant_node
     756             : {
     757           5 :   empty_list_node(type_check_context& context)
     758           5 :     : constant_node(context, "[]")
     759           5 :   { }
     760             : 
     761           5 :   void set_constraint(type_check_context& context) override
     762             :   {
     763           5 :     auto element_sort = context.create_sort_variable();
     764           5 :     constraint = make_is_equal_to_constraint(sort, sort_list::list(element_sort));
     765           5 :   }
     766             : };
     767             : 
     768             : struct empty_set_node final: public constant_node
     769             : {
     770           6 :   empty_set_node(type_check_context& context)
     771           6 :     : constant_node(context, "{}")
     772           6 :   { }
     773             : 
     774           6 :   void set_constraint(type_check_context& context) override
     775             :   {
     776           6 :     auto element_sort = context.create_sort_variable();
     777           6 :     constraint = make_is_equal_to_constraint(sort, sort_set::set_(element_sort));
     778           6 :   }
     779             : };
     780             : 
     781             : struct empty_bag_node final: public constant_node
     782             : {
     783           2 :   empty_bag_node(type_check_context& context)
     784           2 :     : constant_node(context, "{:}")
     785           2 :   { }
     786             : 
     787           2 :   void set_constraint(type_check_context& context) override
     788             :   {
     789           2 :     auto element_sort = context.create_sort_variable();
     790           2 :     constraint = make_is_equal_to_constraint(sort, sort_bag::bag(element_sort));
     791           2 :   }
     792             : };
     793             : 
     794             : struct list_enumeration_node final: public type_check_node
     795             : {
     796          15 :   list_enumeration_node(type_check_context& context, const std::vector<type_check_node_ptr>& children)
     797          15 :     : type_check_node(context, children)
     798          15 :   {}
     799             : 
     800          15 :   void set_constraint(type_check_context& context) override
     801             :   {
     802          15 :     auto element_sort = context.create_sort_variable();
     803          15 :     set_children_constraints(context);
     804             : 
     805          15 :     std::vector<constraint_ptr> alternatives;
     806          15 :     alternatives.push_back(make_is_equal_to_constraint(sort, sort_list::list(element_sort)));
     807          41 :     for (const type_check_node_ptr& child: children)
     808             :     {
     809          26 :       alternatives.push_back(make_subsort_constraint(element_sort, child->sort));
     810             :     }
     811          15 :     constraint = make_and_constraint(alternatives);
     812          15 :   }
     813             : 
     814          25 :   std::string print() const override
     815             :   {
     816          25 :     return print_node_vector("list_enumeration", children);
     817             :   }
     818             : };
     819             : 
     820             : struct bag_enumeration_node final: public type_check_node
     821             : {
     822           2 :   bag_enumeration_node(type_check_context& context, const std::vector<type_check_node_ptr>& children)
     823           2 :     : type_check_node(context, children)
     824           2 :   {}
     825             : 
     826           2 :   void set_constraint(type_check_context& context) override
     827             :   {
     828           2 :     auto element_sort = context.create_sort_variable();
     829           2 :     set_children_constraints(context);
     830             : 
     831           2 :     std::vector<constraint_ptr> alternatives;
     832           2 :     alternatives.push_back(make_is_equal_to_constraint(sort, sort_bag::bag(element_sort)));
     833          12 :     for (std::size_t i = 0; i < children.size(); i++)
     834             :     {
     835          10 :       if (i % 2 == 0)
     836             :       {
     837           5 :         alternatives.push_back(make_subsort_constraint(element_sort, children[i]->sort));
     838             :       }
     839             :       else
     840             :       {
     841           5 :         alternatives.push_back(make_subsort_constraint(sort_nat::nat(), children[i]->sort));
     842             :       }
     843             :     }
     844           2 :     constraint = make_and_constraint(alternatives);
     845           2 :   }
     846             : 
     847           2 :   std::string print() const override
     848             :   {
     849           2 :     return print_node_vector("bag_enumeration", children);
     850             :   }
     851             : };
     852             : 
     853             : struct set_enumeration_node final: public type_check_node
     854             : {
     855           2 :   set_enumeration_node(type_check_context& context, const std::vector<type_check_node_ptr>& children)
     856           2 :     : type_check_node(context, children)
     857           2 :   {}
     858             : 
     859           2 :   void set_constraint(type_check_context& context) override
     860             :   {
     861           2 :     auto element_sort = context.create_sort_variable();
     862           2 :     set_children_constraints(context);
     863             : 
     864           2 :     std::vector<constraint_ptr> alternatives;
     865           2 :     alternatives.push_back(make_is_equal_to_constraint(sort, sort_set::set_(element_sort)));
     866           7 :     for (const type_check_node_ptr& child: children)
     867             :     {
     868           5 :       alternatives.push_back(make_subsort_constraint(element_sort, child->sort));
     869             :     }
     870           2 :     constraint = make_and_constraint(alternatives);
     871           2 :   }
     872             : 
     873           2 :   std::string print() const override
     874             :   {
     875           2 :     return print_node_vector("set_enumeration", children);
     876             :   }
     877             : };
     878             : 
     879             : struct bag_or_set_enumeration_node final: public type_check_node
     880             : {
     881             :   variable v;
     882             : 
     883           2 :   bag_or_set_enumeration_node(type_check_context& context, const variable& v_, type_check_node_ptr x)
     884           2 :     : type_check_node(context, {}), v(v_)
     885             :   {
     886           2 :     children.push_back(x);
     887           2 :   }
     888             : 
     889           2 :   void set_constraint(type_check_context& context) override
     890             :   {
     891           2 :     context.add_context_variable(v);
     892           2 :     set_children_constraints(context);
     893             : 
     894           2 :     auto element_sort = v.sort();
     895           4 :     constraint_ptr set_constraint = make_and_constraint({
     896           2 :       make_is_equal_to_constraint(sort, sort_set::set_(element_sort)),
     897           4 :       make_is_equal_to_constraint(children.front()->sort, sort_bool::bool_())
     898          10 :     });
     899           4 :     constraint_ptr bag_constraint = make_and_constraint({
     900           2 :         make_is_equal_to_constraint(sort, sort_bag::bag(element_sort)),
     901           2 :         make_subsort_constraint(sort_nat::nat(), children.front()->sort)
     902           8 :        });
     903           6 :     constraint = make_or_constraint({ set_constraint, bag_constraint });
     904           2 :     context.remove_context_variable(v);
     905           2 :   }
     906             : 
     907           2 :   std::string print() const override
     908             :   {
     909           2 :     return print_node_vector("bag_or_set_enumeration", children);
     910             :   }
     911             : };
     912             : 
     913             : struct function_update_node final: public type_check_node
     914             : {
     915           5 :   function_update_node(type_check_context& context, type_check_node_ptr x1, type_check_node_ptr x2, type_check_node_ptr x3)
     916           5 :     : type_check_node(context, {})
     917             :   {
     918           5 :     children.push_back(x1);
     919           5 :     children.push_back(x2);
     920           5 :     children.push_back(x3);
     921           5 :   }
     922             : 
     923           6 :   std::string print() const override
     924             :   {
     925           6 :     return print_node_vector("function_update", children);
     926             :   }
     927             : };
     928             : 
     929             : struct application_node final: public type_check_node
     930             : {
     931             :   std::size_t arity;
     932             : 
     933           3 :   application_node(type_check_context& context, type_check_node_ptr head, const std::vector<type_check_node_ptr>& arguments)
     934           3 :     : type_check_node(context, {}), arity(arguments.size())
     935             :   {
     936           3 :     children.push_back(head);
     937           8 :     for (const auto& arg: arguments)
     938             :     {
     939           5 :       children.push_back(arg);
     940             :     }
     941           3 :   }
     942             : 
     943           3 :   void set_constraint(type_check_context& context) override
     944             :   {
     945           3 :     set_children_constraints(context);
     946             : 
     947           3 :     const sort_expression& codomain = sort;
     948           3 :     std::vector<constraint_ptr> alternatives;
     949           3 :     std::vector<sort_expression> domain;
     950           8 :     for (std::size_t i = 0; i < arity; i++)
     951             :     {
     952           5 :       domain.push_back(children[i+1]->sort);
     953             :     }
     954           3 :     alternatives.push_back(make_is_equal_to_constraint(children[0]->sort, function_sort(sort_expression_list(domain.begin(), domain.end()), codomain)));
     955             : 
     956             :     // add missing constraints for if application
     957             :     // TODO: handle this in a more structured way
     958           3 :     if (children[0]->print() == "id(if)")
     959             :     {
     960           1 :       alternatives.push_back(make_subsort_constraint(codomain, children[1]->sort));
     961           1 :       alternatives.push_back(make_subsort_constraint(codomain, children[2]->sort));
     962             :     }
     963             : 
     964           3 :     constraint = make_and_constraint(alternatives);
     965           3 :   }
     966             : 
     967           6 :   std::string print() const override
     968             :   {
     969           6 :     return print_node_vector("application", children);
     970             :   }
     971             : };
     972             : 
     973             : struct unary_operator_node: public type_check_node
     974             : {
     975             :   std::string name;
     976             : 
     977          21 :   unary_operator_node(type_check_context& context, const std::string& name_, type_check_node_ptr arg)
     978          42 :     : type_check_node(context, { arg }), name(name_)
     979          21 :   {}
     980             : 
     981          31 :   virtual ~unary_operator_node() {}
     982             : 
     983          10 :   void set_constraint(type_check_context& context) override
     984             :   {
     985          10 :     set_children_constraints(context);
     986             : 
     987          10 :     std::pair<function_sort_list, function_sort_list> p = context.find_matching_functions(name, 1);
     988          10 :     std::vector<constraint_ptr> alternatives;
     989          39 :     for (const function_sort& s: p.first + p.second)
     990             :     {
     991          87 :       alternatives.push_back(make_and_constraint({
     992          29 :           make_subsort_constraint(children[0]->sort, s.domain().front()),
     993             :           make_subsort_constraint(s.codomain(), sort)
     994             :          })
     995             :       );
     996          10 :     }
     997          10 :     constraint = make_or_constraint(alternatives);
     998          10 :   }
     999             : 
    1000          16 :   std::string print() const override
    1001             :   {
    1002          16 :     std::ostringstream out;
    1003          16 :     out << "unary_operator(" << name << ", " << children.front()->print() << ")";
    1004          32 :     return out.str();
    1005          16 :   }
    1006             : };
    1007             : 
    1008             : struct forall_node final: public type_check_node
    1009             : {
    1010             :   variable_list variables;
    1011             : 
    1012           3 :   forall_node(type_check_context& context, const variable_list& variables_, type_check_node_ptr arg)
    1013           6 :     : type_check_node(context, { arg }), variables(variables_)
    1014           3 :   {}
    1015             : 
    1016           3 :   void set_constraint(type_check_context& context) override
    1017             :   {
    1018           3 :     context.add_context_variables(variables);
    1019           3 :     set_children_constraints(context);
    1020             : 
    1021           3 :     constraint = make_is_equal_to_constraint(sort, sort_bool::bool_());
    1022           3 :     context.remove_context_variables(variables);
    1023           3 :   }
    1024             : 
    1025           3 :   std::string print() const override
    1026             :   {
    1027           3 :     std::ostringstream out;
    1028           3 :     out << "forall(" << data::pp(variables) << ". " << children.front()->print() << ")";
    1029           6 :     return out.str();
    1030           3 :   }
    1031             : };
    1032             : 
    1033             : struct exists_node final: public type_check_node
    1034             : {
    1035             :   variable_list variables;
    1036             : 
    1037           2 :   exists_node(type_check_context& context, const variable_list& variables_, type_check_node_ptr arg)
    1038           4 :     : type_check_node(context, { arg }), variables(variables_)
    1039           2 :   {}
    1040             : 
    1041           2 :   void set_constraint(type_check_context& context) override
    1042             :   {
    1043           2 :     context.add_context_variables(variables);
    1044           2 :     set_children_constraints(context);
    1045             : 
    1046           2 :     constraint = make_is_equal_to_constraint(sort, sort_bool::bool_());
    1047           2 :     context.remove_context_variables(variables);
    1048           2 :   }
    1049             : 
    1050           2 :   std::string print() const override
    1051             :   {
    1052           2 :     std::ostringstream out;
    1053           2 :     out << "exists(" << data::pp(variables) << ". " << children.front()->print() << ")";
    1054           4 :     return out.str();
    1055           2 :   }
    1056             : };
    1057             : 
    1058             : struct lambda_node final: public unary_operator_node
    1059             : {
    1060             :   variable_list variables;
    1061             : 
    1062          11 :   lambda_node(type_check_context& context, const variable_list& variables_, type_check_node_ptr arg)
    1063          11 :     : unary_operator_node(context, "lambda", arg), variables(variables_)
    1064          11 :   {}
    1065             : 
    1066           7 :   void set_constraint(type_check_context& context) override
    1067             :   {
    1068           7 :     context.add_context_variables(variables);
    1069           7 :     set_children_constraints(context);
    1070             : 
    1071           7 :     constraint = make_true_constraint();
    1072           7 :     context.remove_context_variables(variables);
    1073           7 :   }
    1074             : 
    1075          20 :   std::string print() const override
    1076             :   {
    1077          20 :     std::ostringstream out;
    1078          20 :     out << "lambda(" << data::pp(variables) << ". " << children.front()->print() << ")";
    1079          40 :     return out.str();
    1080          20 :   }
    1081             : };
    1082             : 
    1083             : struct binary_operator_node final: public type_check_node
    1084             : {
    1085             :   std::string name;
    1086             : 
    1087          60 :   binary_operator_node(type_check_context& context, const std::string& name_, type_check_node_ptr left, type_check_node_ptr right)
    1088         180 :     : type_check_node(context, { left, right }), name(name_)
    1089          60 :   {}
    1090             : 
    1091          58 :   void set_constraint(type_check_context& context) override
    1092             :   {
    1093          58 :     set_children_constraints(context);
    1094             : 
    1095          58 :     std::pair<function_sort_list, function_sort_list> p = context.find_matching_functions(name, 2);
    1096          58 :     std::vector<constraint_ptr> alternatives;
    1097         387 :     for (const function_sort& s: p.first + p.second)
    1098             :     {
    1099         329 :       auto i = s.domain().begin();
    1100         329 :       const sort_expression& left = *i++;
    1101         329 :       const sort_expression& right = *i;
    1102        1645 :       alternatives.push_back(make_and_constraint({
    1103         329 :           make_subsort_constraint(children[0]->sort, left),
    1104         329 :           make_subsort_constraint(children[1]->sort, right),
    1105             :           make_subsort_constraint(s.codomain(), sort)
    1106             :          })
    1107             :       );
    1108          58 :     }
    1109          58 :     constraint = make_or_constraint(alternatives);
    1110          58 :   }
    1111             : 
    1112         108 :   std::string print() const override
    1113             :   {
    1114         108 :     std::ostringstream out;
    1115         108 :     out << "binary_operator(" << name << ", " << children[0]->print() << ", " << children[1]->print() << ")";
    1116         216 :     return out.str();
    1117         108 :   }
    1118             : };
    1119             : 
    1120             : struct where_clause_node final: public type_check_node
    1121             : {
    1122             :   std::vector<variable> variables;
    1123             : 
    1124          13 :   where_clause_node(type_check_context& context, type_check_node_ptr body, const std::vector<std::pair<std::string, type_check_node_ptr> >& assignments)
    1125          13 :     : type_check_node(context, {})
    1126             :   {
    1127          13 :     children.push_back(body);
    1128          38 :     for (const std::pair<std::string, type_check_node_ptr>& a: assignments)
    1129             :     {
    1130          25 :       children.push_back(a.second);
    1131          25 :       variables.push_back(variable(a.first, a.second->sort));
    1132             :     }
    1133          13 :   }
    1134             : 
    1135          13 :   void set_constraint(type_check_context& context) override
    1136             :   {
    1137          13 :     variable_list v(variables.begin(), variables.end());
    1138          13 :     context.add_context_variables(v);
    1139          13 :     set_children_constraints(context);
    1140          13 :     context.remove_context_variables(v);
    1141             : 
    1142          13 :     std::vector<constraint_ptr> constraints;
    1143          13 :     constraints.push_back(make_is_equal_to_constraint(sort, children[0]->sort));
    1144          13 :     auto i = variables.begin();
    1145          13 :     auto j = ++children.begin();
    1146          38 :     for (; i != variables.end(); ++i, ++j)
    1147             :     {
    1148          25 :       constraints.push_back(make_is_equal_to_constraint((*j)->sort, i->sort()));
    1149             :     }
    1150          13 :     constraint = make_and_constraint(constraints);
    1151          13 :   }
    1152             : 
    1153          13 :   std::string print() const override
    1154             :   {
    1155          13 :     std::ostringstream out;
    1156          13 :     return print_node_vector("where_clause", children);
    1157             :     return out.str();
    1158          13 :   }
    1159             : };
    1160             : 
    1161             : struct type_check_tree_generator final: public detail::data_expression_actions
    1162             : {
    1163             :   type_check_context& context;
    1164             : 
    1165          71 :   type_check_tree_generator(type_check_context& context_, const core::parser& parser_)
    1166          71 :     : data_expression_actions(parser_), context(context_)
    1167          71 :   {}
    1168             : 
    1169          22 :   std::vector<type_check_node_ptr> parse_DataExprList(const core::parse_node& node) const
    1170             :   {
    1171          68 :     return parse_vector<type_check_node_ptr>(node, "DataExpr", [&](const core::parse_node& node) { return parse_DataExpr(node); });
    1172             :   }
    1173             : 
    1174           2 :   std::vector<type_check_node_ptr> parse_BagEnumEltList(const core::parse_node& node) const
    1175             :   {
    1176           2 :     return parse_DataExprList(node);
    1177             :   }
    1178             : 
    1179          25 :   std::pair<std::string, type_check_node_ptr> parse_Assignment(const core::parse_node& node) const
    1180             :   {
    1181          50 :     return std::make_pair(parse_Id(node.child(0)), parse_DataExpr(node.child(2)));
    1182             :   }
    1183             : 
    1184          13 :   std::vector<std::pair<std::string, type_check_node_ptr> > parse_AssignmentList(const core::parse_node& node) const
    1185             :   {
    1186          38 :     return parse_vector<std::pair<std::string, type_check_node_ptr> >(node, "Assignment", [&](const core::parse_node& node) { return parse_Assignment(node); });
    1187             :   }
    1188             : 
    1189         326 :   type_check_node_ptr parse_DataExpr(const core::parse_node& node) const
    1190             :   {
    1191         326 :     assert(symbol_name(node) == "DataExpr");
    1192         326 :     if ((node.child_count() == 1) && (symbol_name(node.child(0)) == "Id")) { return type_check_node_ptr(new id_node(context, parse_Id(node.child(0)))); }
    1193         242 :     else if ((node.child_count() == 1) && (symbol_name(node.child(0)) == "Number")) { return type_check_node_ptr(new number_node(context, parse_Number(node.child(0)))); }
    1194         168 :     else if ((node.child_count() == 1) && (symbol_name(node.child(0)) == "true")) { return type_check_node_ptr(new true_node(context)); }
    1195         156 :     else if ((node.child_count() == 1) && (symbol_name(node.child(0)) == "false")) { return type_check_node_ptr(new false_node(context)); }
    1196         146 :     else if ((node.child_count() == 2) && (symbol_name(node.child(0)) == "[") && (symbol_name(node.child(1)) == "]")) { return type_check_node_ptr(new empty_list_node(context)); }
    1197         141 :     else if ((node.child_count() == 2) && (symbol_name(node.child(0)) == "{") && (symbol_name(node.child(1)) == "}")) { return type_check_node_ptr(new empty_set_node(context)); }
    1198         135 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "{") && (symbol_name(node.child(1)) == ":") && (symbol_name(node.child(2)) == "}")) { return type_check_node_ptr(new empty_bag_node(context)); }
    1199         148 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "[") && (symbol_name(node.child(1)) == "DataExprList") && (symbol_name(node.child(2)) == "]")) { return type_check_node_ptr(new list_enumeration_node(context, parse_DataExprList(node.child(1)))); }
    1200         120 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "{") && (symbol_name(node.child(1)) == "BagEnumEltList") && (symbol_name(node.child(2)) == "}")) { return type_check_node_ptr(new bag_enumeration_node(context, parse_BagEnumEltList(node.child(1)))); }
    1201         118 :     else if ((node.child_count() == 5) && (symbol_name(node.child(0)) == "{") && (symbol_name(node.child(1)) == "VarDecl") && (symbol_name(node.child(2)) == "|") && (symbol_name(node.child(3)) == "DataExpr") && (symbol_name(node.child(4)) == "}")) { return type_check_node_ptr(new bag_or_set_enumeration_node(context, parse_VarDecl(node.child(1)), parse_DataExpr(node.child(3)))); }
    1202         116 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "{") && (symbol_name(node.child(1)) == "DataExprList") && (symbol_name(node.child(2)) == "}")) { return type_check_node_ptr(new set_enumeration_node(context, parse_DataExprList(node.child(1)))); }
    1203         117 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "(") && (symbol_name(node.child(1)) == "DataExpr") && (symbol_name(node.child(2)) == ")")) { return parse_DataExpr(node.child(1)); }
    1204         112 :     else if ((node.child_count() == 6) && (symbol_name(node.child(0)) == "DataExpr") && (symbol_name(node.child(1)) == "[") && (symbol_name(node.child(2)) == "DataExpr") && (symbol_name(node.child(3)) == "->") && (symbol_name(node.child(4)) == "DataExpr") && (symbol_name(node.child(5)) == "]")) { return type_check_node_ptr(new function_update_node(context, parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)), parse_DataExpr(node.child(4)))); }
    1205         105 :     else if ((node.child_count() == 4) && (symbol_name(node.child(0)) == "DataExpr") && (symbol_name(node.child(1)) == "(") && (symbol_name(node.child(2)) == "DataExprList") && (symbol_name(node.child(3)) == ")")) { return type_check_node_ptr(new application_node(context, parse_DataExpr(node.child(0)), parse_DataExprList(node.child(2)))); }
    1206         104 :     else if ((node.child_count() == 2) && (symbol_name(node.child(0)) == "!") && (symbol_name(node.child(1)) == "DataExpr")) { return type_check_node_ptr(new unary_operator_node(context, "!", parse_DataExpr(node.child(1)))); }
    1207          98 :     else if ((node.child_count() == 2) && (symbol_name(node.child(0)) == "-") && (symbol_name(node.child(1)) == "DataExpr")) { return type_check_node_ptr(new unary_operator_node(context, "-", parse_DataExpr(node.child(1)))); }
    1208          91 :     else if ((node.child_count() == 2) && (symbol_name(node.child(0)) == "#") && (symbol_name(node.child(1)) == "DataExpr")) { return type_check_node_ptr(new unary_operator_node(context, "#", parse_DataExpr(node.child(1)))); }
    1209          92 :     else if ((node.child_count() == 4) && (symbol_name(node.child(0)) == "forall") && (symbol_name(node.child(1)) == "VarsDeclList") && (symbol_name(node.child(2)) == ".") && (symbol_name(node.child(3)) == "DataExpr")) { return type_check_node_ptr(new forall_node(context, parse_VarsDeclList(node.child(1)), parse_DataExpr(node.child(3)))); }
    1210          88 :     else if ((node.child_count() == 4) && (symbol_name(node.child(0)) == "exists") && (symbol_name(node.child(1)) == "VarsDeclList") && (symbol_name(node.child(2)) == ".") && (symbol_name(node.child(3)) == "DataExpr")) { return type_check_node_ptr(new exists_node(context, parse_VarsDeclList(node.child(1)), parse_DataExpr(node.child(3)))); }
    1211          95 :     else if ((node.child_count() == 4) && (symbol_name(node.child(0)) == "lambda") && (symbol_name(node.child(1)) == "VarsDeclList") && (symbol_name(node.child(2)) == ".") && (symbol_name(node.child(3)) == "DataExpr")) { return type_check_node_ptr(new lambda_node(context, parse_VarsDeclList(node.child(1)), parse_DataExpr(node.child(3)))); }
    1212          73 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "=>" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "=>" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1213          74 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "&&" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "&&" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1214          72 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "||" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "||" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1215          84 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "==" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "==" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1216          60 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "!=" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "!=" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1217          60 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "<"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "<"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1218          62 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "<=" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "<=" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1219          59 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == ">=" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, ">=" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1220          59 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == ">"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, ">"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1221          56 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "in" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "in" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1222          54 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "|>" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "|>" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1223          54 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "<|" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "<|" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1224          63 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "++" ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "++" , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1225          73 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "+"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "+"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1226          17 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "-"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "-"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1227          17 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "/"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "/"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1228          17 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "div") && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "div", parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1229          19 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "mod") && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "mod", parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1230          17 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "*"  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "*"  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1231          13 :     else if ((node.child_count() == 3) && (symbol_name(node.child(0)) == "DataExpr") && (node.child(1).string() == "."  ) && (symbol_name(node.child(2)) == "DataExpr")) { return type_check_node_ptr(new binary_operator_node(context, "."  , parse_DataExpr(node.child(0)), parse_DataExpr(node.child(2)))); }
    1232          26 :     else if ((node.child_count() == 4) && (symbol_name(node.child(0)) == "DataExpr") && (symbol_name(node.child(1)) == "whr") && (symbol_name(node.child(2)) == "AssignmentList") && (symbol_name(node.child(3)) == "end")) { return type_check_node_ptr(new where_clause_node(context, { parse_DataExpr(node.child(0)) }, parse_AssignmentList(node.child(2)))); }
    1233           0 :     throw core::parse_node_unexpected_exception(m_parser, node);
    1234             :   }
    1235             : };
    1236             : 
    1237             : inline
    1238          94 : std::pair<sort_expression_list, sort_expression_list> type_check_context::find_matching_constants(const std::string& name) const
    1239             : {
    1240          94 :   sort_expression_list system_result;
    1241          94 :   sort_expression_list user_result;
    1242          94 :   auto i = system_constants.find(core::identifier_string(name));
    1243          94 :   if (i != system_constants.end())
    1244             :   {
    1245          14 :     system_result = i->second;
    1246             :   }
    1247          94 :   auto j = user_constants.find(core::identifier_string(name));
    1248          94 :   if (j != user_constants.end())
    1249             :   {
    1250           0 :     user_result = { j->second };
    1251             :   }
    1252         188 :   return std::make_pair(system_result, user_result);
    1253          94 : }
    1254             : 
    1255             : inline
    1256          68 : function_sort_list filter_sorts(const function_sort_list& sorts, std::size_t arity)
    1257             : {
    1258          68 :   std::vector<function_sort> result;
    1259         458 :   for (const function_sort& sort: sorts)
    1260             :   {
    1261         390 :     if (sort.domain().size() == arity)
    1262             :     {
    1263         358 :       result.push_back(sort);
    1264             :     }
    1265             :   }
    1266         136 :   return function_sort_list(result.begin(), result.end());
    1267          68 : }
    1268             : 
    1269             : inline
    1270          68 : std::pair<function_sort_list, function_sort_list> type_check_context::find_matching_functions(const std::string& name, std::size_t arity) const
    1271             : {
    1272          68 :   function_sort_list system_result;
    1273          68 :   function_sort_list user_result;
    1274          68 :   auto i = system_functions.find(core::identifier_string(name));
    1275          68 :   if (i != system_functions.end())
    1276             :   {
    1277          68 :     system_result = filter_sorts(i->second, arity);
    1278             :   }
    1279          68 :   auto j = user_functions.find(core::identifier_string(name));
    1280          68 :   if (j != user_functions.end())
    1281             :   {
    1282           0 :     user_result = filter_sorts(j->second, arity);
    1283             :   }
    1284         136 :   return { replace_untyped_sorts(system_result), user_result };
    1285          68 : }
    1286             : 
    1287             : inline
    1288          80 : std::pair<function_sort_list, function_sort_list> type_check_context::find_matching_functions(const std::string& name) const
    1289             : {
    1290          80 :   function_sort_list system_result;
    1291          80 :   function_sort_list user_result;
    1292          80 :   auto i = system_functions.find(core::identifier_string(name));
    1293          80 :   if (i != system_functions.end())
    1294             :   {
    1295           1 :     system_result = i->second;
    1296             :   }
    1297          80 :   auto j = user_functions.find(core::identifier_string(name));
    1298          80 :   if (j != user_functions.end())
    1299             :   {
    1300           0 :     user_result = j->second;
    1301             :   }
    1302         160 :   return { replace_untyped_sorts(system_result), user_result };
    1303          80 : }
    1304             : 
    1305             : inline
    1306          80 : std::vector<sort_expression> type_check_context::find_matching_variables(const std::string& name) const
    1307             : {
    1308          80 :   std::vector<sort_expression> result;
    1309          80 :   auto i = declared_variables.find(core::identifier_string(name));
    1310          80 :   if (i != declared_variables.end())
    1311             :   {
    1312          77 :     result.push_back(i->second.back());
    1313             :   }
    1314         160 :   return result;
    1315           0 : }
    1316             : 
    1317             : inline
    1318         321 : void print_node(const type_check_node_ptr& node)
    1319             : {
    1320         321 :   std::cout << "\nnode = " << node->print() << std::endl;
    1321         321 :   std::cout << "sort = " << node->sort << std::endl;
    1322         321 :   std::cout << "constraint = " << node->constraint->print() << std::endl;
    1323         571 :   for (const type_check_node_ptr& child: node->children)
    1324             :   {
    1325         250 :     print_node(child);
    1326             :   }
    1327         321 : }
    1328             : 
    1329             : // TODO: This design is ugly, but for the moment it seems the easiest solution to modify
    1330             : // the constraint tree
    1331             : inline
    1332           0 : constraint_ptr substitute_constraint(constraint_ptr p, const sort_substitution& sigma)
    1333             : {
    1334             :   {
    1335           0 :     or_constraint* x = dynamic_cast<or_constraint*>(p.get());
    1336           0 :     if (x)
    1337             :     {
    1338           0 :       for (constraint_ptr& q: x->alternatives)
    1339             :       {
    1340           0 :         q = substitute_constraint(q, sigma);
    1341             :       }
    1342           0 :       return p;
    1343             :     }
    1344             :   }
    1345             :   {
    1346           0 :     and_constraint* x = dynamic_cast<and_constraint*>(p.get());
    1347           0 :     if (x)
    1348             :     {
    1349           0 :       for (constraint_ptr& q: x->alternatives)
    1350             :       {
    1351           0 :         q = substitute_constraint(q, sigma);
    1352             :       }
    1353           0 :       return p;
    1354             :     }
    1355             :   }
    1356             :   {
    1357           0 :     is_equal_to_constraint* x = dynamic_cast<is_equal_to_constraint*>(p.get());
    1358           0 :     if (x)
    1359             :     {
    1360           0 :       sort_expression s1 = substitute(x->s1, sigma);
    1361           0 :       sort_expression s2 = substitute(x->s2, sigma);
    1362           0 :       return make_is_equal_to_constraint(s1, s2);
    1363           0 :     }
    1364             :   }
    1365           0 :   return p;
    1366             : }
    1367             : 
    1368             : } // namespace data
    1369             : 
    1370             : } // namespace mcrl2
    1371             : 
    1372             : #endif // MCRL2_DATA_EXPERIMENTAL_TYPE_CHECK_TREE_H

Generated by: LCOV version 1.14