LCOV - code coverage report
Current view: top level - modal_formula/include/mcrl2/modal_formula - typecheck.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 226 326 69.3 %
Date: 2024-04-21 03:44:01 Functions: 40 56 71.4 %
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/modal_formula/typecheck.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_MODAL_FORMULA_TYPECHECK_H
      13             : #define MCRL2_MODAL_FORMULA_TYPECHECK_H
      14             : 
      15             : #include "mcrl2/lps/typecheck.h"
      16             : #include "mcrl2/modal_formula/detail/state_variable_context.h"
      17             : #include "mcrl2/modal_formula/is_monotonous.h"
      18             : #include "mcrl2/modal_formula/normalize_sorts.h"
      19             : 
      20             : namespace mcrl2
      21             : {
      22             : 
      23             : namespace action_formulas
      24             : {
      25             : 
      26             : namespace detail
      27             : {
      28             : 
      29             : struct typecheck_builder: public action_formula_builder<typecheck_builder>
      30             : {
      31             :   typedef action_formula_builder<typecheck_builder> super;
      32             :   using super::apply;
      33             : 
      34             :   data::data_type_checker& m_data_type_checker;
      35             :   data::detail::variable_context m_variable_context;
      36             :   const process::detail::action_context& m_action_context;
      37             : 
      38         230 :   typecheck_builder(data::data_type_checker& data_typechecker,
      39             :                     const data::detail::variable_context& variable_context,
      40             :                     const process::detail::action_context& action_context
      41             :                    )
      42         230 :     : m_data_type_checker(data_typechecker),
      43         230 :       m_variable_context(variable_context),
      44         230 :       m_action_context(action_context)
      45         230 :   {}
      46             : 
      47         171 :   process::action typecheck_action(const core::identifier_string& name, const data::data_expression_list& parameters)
      48             :   {
      49         171 :     return process::typecheck_action(name, parameters, m_data_type_checker, m_variable_context, m_action_context);
      50             :   }
      51             : 
      52             :   template <class T>
      53           0 :   void apply(T& result, const data::data_expression& x)
      54             :   {
      55           0 :     result = m_data_type_checker.typecheck_data_expression(x, data::sort_bool::bool_(), m_variable_context);
      56           0 :   }
      57             : 
      58             :   template <class T>
      59           0 :   void apply(T& result, const action_formulas::at& x)
      60             :   {
      61           0 :     data::data_expression new_time = m_data_type_checker.typecheck_data_expression(x.time_stamp(), data::sort_real::real_(), m_variable_context);
      62           0 :     make_at(result, [&](action_formula& r){ (*this).apply(r, x.operand()); }, new_time);
      63           0 :   }
      64             : 
      65             :   template <class T>
      66         179 :   void apply(T& result, const process::untyped_multi_action& x)
      67             :   {
      68             :     // If x has size 1, first try to type check it as a data expression.
      69         179 :     if (x.actions().size() == 1)
      70             :     {
      71         171 :       const data::untyped_data_parameter& y = x.actions().front();
      72             :       try
      73             :       {
      74         171 :         result = data::typecheck_untyped_data_parameter(m_data_type_checker, y.name(), y.arguments(), data::sort_bool::bool_(), m_variable_context);
      75           0 :         return;
      76             :       }
      77         171 :       catch (mcrl2::runtime_error& )
      78             :       {
      79             :         // skip
      80             :       }
      81             :     }
      82             :     // Type check it as a multi action
      83         179 :     process::action_list new_arguments;
      84         529 :     for (const data::untyped_data_parameter& a: x.actions())
      85             :     {
      86         171 :       new_arguments.push_front(typecheck_action(a.name(), a.arguments()));
      87             :     }
      88         179 :     new_arguments = atermpp::reverse(new_arguments);
      89         179 :     result = action_formulas::multi_action(new_arguments);
      90         179 :   }
      91             : 
      92             :   template <class T>
      93           3 :   void apply(T& result, const action_formulas::forall& x)
      94             :   {
      95             :     try
      96             :     {
      97           3 :       auto m_variable_context_copy = m_variable_context;
      98           3 :       m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
      99           3 :       action_formula body;
     100           3 :       (*this).apply(body, x.body());
     101           3 :       m_variable_context = m_variable_context_copy;
     102           3 :       result = forall(x.variables(), body);
     103           3 :     }
     104           0 :     catch (mcrl2::runtime_error& e)
     105             :     {
     106           0 :       throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + action_formulas::pp(x));
     107             :     }
     108           3 :   }
     109             : 
     110             :   template <class T>
     111           2 :   void apply(T& result,  const action_formulas::exists& x)
     112             :   {
     113             :     try
     114             :     {
     115           2 :       auto m_variable_context_copy = m_variable_context;
     116           2 :       m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     117           2 :       action_formula body;
     118           2 :       (*this).apply(body, x.body());
     119           2 :       m_variable_context = m_variable_context_copy;
     120           2 :       result = exists(x.variables(), body);
     121           2 :     }
     122           0 :     catch (mcrl2::runtime_error& e)
     123             :     {
     124           0 :       throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + action_formulas::pp(x));
     125             :     }
     126           2 :   }
     127             : };
     128             : 
     129             : inline
     130         230 : typecheck_builder make_typecheck_builder(
     131             :                     data::data_type_checker& data_typechecker,
     132             :                     const data::detail::variable_context& variables,
     133             :                     const process::detail::action_context& actions
     134             :                    )
     135             : {
     136         230 :   return typecheck_builder(data_typechecker, variables, actions);
     137             : }
     138             : 
     139             : } // namespace detail
     140             : 
     141             : template <typename ActionLabelContainer = std::vector<state_formulas::variable>, typename VariableContainer = std::vector<data::variable> >
     142             : action_formula typecheck_action_formula(const action_formula& x,
     143             :                                         const data::data_specification& dataspec,
     144             :                                         const VariableContainer& variables,
     145             :                                         const ActionLabelContainer& actions
     146             :                                        )
     147             : {
     148             :   data::data_type_checker data_typechecker(dataspec);
     149             :   data::detail::variable_context variable_context;
     150             :   variable_context.add_context_variables(variables, data_typechecker);
     151             :   process::detail::action_context action_context;
     152             :   action_context.add_context_action_labels(actions, data_typechecker);
     153             :   action_formula result;
     154             :   detail::make_typecheck_builder(data_typechecker, variable_context, action_context).
     155             :              apply(result, action_formulas::normalize_sorts(x, data_typechecker.typechecked_data_specification()));
     156             :   return result;
     157             : }
     158             : 
     159             : inline
     160             : action_formula typecheck_action_formula(const action_formula& x, const lps::stochastic_specification& lpsspec)
     161             : {
     162             :   return typecheck_action_formula(x, lpsspec.data(), lpsspec.global_variables(), lpsspec.action_labels());
     163             : }
     164             : 
     165             : } // namespace action_formulas
     166             : 
     167             : namespace regular_formulas
     168             : {
     169             : 
     170             : namespace detail
     171             : {
     172             : 
     173             : struct typecheck_builder: public regular_formula_builder<typecheck_builder>
     174             : {
     175             :   typedef regular_formula_builder<typecheck_builder> super;
     176             :   using super::apply;
     177             : 
     178             :   data::data_type_checker& m_data_type_checker;
     179             :   const data::detail::variable_context& m_variable_context;
     180             :   const process::detail::action_context& m_action_context;
     181             : 
     182         225 :   typecheck_builder(data::data_type_checker& data_typechecker,
     183             :                     const data::detail::variable_context& variables,
     184             :                     const process::detail::action_context& actions
     185             :                    )
     186         225 :     : m_data_type_checker(data_typechecker),
     187         225 :       m_variable_context(variables),
     188         225 :       m_action_context(actions)
     189         225 :   {}
     190             : 
     191           0 :   data::data_expression make_fbag_union(const data::data_expression& left, const data::data_expression& right)
     192             :   {
     193           0 :     const data::sort_expression& s = atermpp::down_cast<data::application>(left).head().sort();
     194           0 :     const data::container_sort& cs = atermpp::down_cast<data::container_sort>(s);
     195           0 :     return data::sort_fbag::union_(cs.element_sort(), left, right);
     196           0 :   }
     197             : 
     198           0 :   data::data_expression make_bag_union(const data::data_expression& left, const data::data_expression& right)
     199             :   {
     200           0 :     const data::sort_expression& s = atermpp::down_cast<data::application>(left).head().sort();
     201           0 :     const data::container_sort& cs = atermpp::down_cast<data::container_sort>(s);
     202           0 :     return data::sort_bag::union_(cs.element_sort(), left, right);
     203           0 :   }
     204             : 
     205           0 :   data::data_expression make_fset_union(const data::data_expression& left, const data::data_expression& right)
     206             :   {
     207           0 :     const data::sort_expression& s = atermpp::down_cast<data::application>(left).head().sort();
     208           0 :     const data::container_sort& cs = atermpp::down_cast<data::container_sort>(s);
     209           0 :     return data::sort_fset::union_(cs.element_sort(), left, right);
     210           0 :   }
     211             : 
     212           0 :   data::data_expression make_set_union(const data::data_expression& left, const data::data_expression& right)
     213             :   {
     214           0 :     const data::sort_expression& s = atermpp::down_cast<data::application>(left).head().sort();
     215           0 :     const data::container_sort& cs = atermpp::down_cast<data::container_sort>(s);
     216           0 :     return data::sort_set::union_(cs.element_sort(), left, right);
     217           0 :   }
     218             : 
     219           0 :   data::data_expression make_plus(const data::data_expression& left, const data::data_expression& right)
     220             :   {
     221           0 :     if (data::sort_real::is_real(left.sort()) || data::sort_real::is_real(right.sort()))
     222             :     {
     223           0 :       return data::sort_real::plus(left, right);
     224             :     }
     225           0 :     else if (data::sort_int::is_int(left.sort()) || data::sort_int::is_int(right.sort()))
     226             :     {
     227           0 :       return data::sort_int::plus(left, right);
     228             :     }
     229           0 :     else if (data::sort_nat::is_nat(left.sort()) || data::sort_nat::is_nat(right.sort()))
     230             :     {
     231           0 :       return data::sort_nat::plus(left, right);
     232             :     }
     233           0 :     else if (data::sort_pos::is_pos(left.sort()) || data::sort_pos::is_pos(right.sort()))
     234             :     {
     235           0 :       return data::sort_pos::plus(left, right);
     236             :     }
     237           0 :     else if (data::sort_bag::is_union_application(left) || data::sort_bag::is_union_application(right))
     238             :     {
     239           0 :       return make_bag_union(left, right);
     240             :     }
     241           0 :     else if (data::sort_fbag::is_union_application(left) || data::sort_fbag::is_union_application(right))
     242             :     {
     243           0 :       return make_fbag_union(left, right);
     244             :     }
     245           0 :     else if (data::sort_set::is_union_application(left) || data::sort_set::is_union_application(right))
     246             :     {
     247           0 :       return make_set_union(left, right);
     248             :     }
     249           0 :     else if (data::sort_fset::is_union_application(left) || data::sort_fset::is_union_application(right))
     250             :     {
     251           0 :       return make_fset_union(left, right);
     252             :     }
     253           0 :     throw mcrl2::runtime_error("could not typecheck " + data::pp(left) + " + " + data::pp(right));
     254             :   }
     255             : 
     256           0 :   data::data_expression make_element_at(const data::data_expression& left, const data::data_expression& right) const
     257             :   {
     258           0 :     const data::sort_expression& s = atermpp::down_cast<data::application>(left).head().sort();
     259           0 :     const data::container_sort& cs = atermpp::down_cast<data::container_sort>(s);
     260           0 :     return data::sort_list::element_at(cs.element_sort(), left, right);
     261           0 :   }
     262             : 
     263             :   template <class T>
     264           5 :   void apply(T& result, const regular_formulas::untyped_regular_formula& x)
     265             :   {
     266           5 :     regular_formula left;
     267           5 :     (*this).apply(left, x.left());
     268           5 :     regular_formula right;
     269           5 :     (*this).apply(right, x.right());
     270           5 :     if (data::is_data_expression(left) && data::is_data_expression(right))
     271             :     {
     272           0 :       if (x.name() == core::identifier_string("."))
     273             :       {
     274           0 :         result = make_element_at(atermpp::down_cast<data::data_expression>(left), atermpp::down_cast<data::data_expression>(right));
     275             :       }
     276             :       else
     277             :       {
     278           0 :         result = make_plus(atermpp::down_cast<data::data_expression>(left), atermpp::down_cast<data::data_expression>(right));
     279             :       }
     280             :     }
     281             :     else
     282             :     {
     283           5 :       if (x.name() == core::identifier_string("."))
     284             :       {
     285           3 :         result = seq(left, right);
     286             :       }
     287             :       else
     288             :       {
     289           2 :         result = alt(left, right);
     290             :       }
     291             :     }
     292           5 :   }
     293             : 
     294             :   /* Has to be a regular formula as result.... */
     295             :   // template <class T>A
     296         230 :   void apply(regular_formula& result, const action_formulas::action_formula& x)
     297             :   {
     298         230 :     action_formulas::detail::make_typecheck_builder(m_data_type_checker, m_variable_context, m_action_context).apply(result, x);
     299         230 :   }
     300             : };
     301             : 
     302             : inline
     303         225 : typecheck_builder make_typecheck_builder(
     304             :                     data::data_type_checker& data_typechecker,
     305             :                     const data::detail::variable_context& variables,
     306             :                     const process::detail::action_context& actions
     307             :                    )
     308             : {
     309         225 :   return typecheck_builder(data_typechecker, variables, actions);
     310             : }
     311             : 
     312             : } // namespace detail
     313             : 
     314             : template <typename ActionLabelContainer = std::vector<state_formulas::variable>, typename VariableContainer = std::vector<data::variable> >
     315             : regular_formula typecheck_regular_formula(const regular_formula& x,
     316             :                                           const data::data_specification& dataspec,
     317             :                                           const VariableContainer& variables,
     318             :                                           const ActionLabelContainer& actions
     319             :                                          )
     320             : {
     321             :   data::data_type_checker data_typechecker(dataspec);
     322             :   data::detail::variable_context variable_context;
     323             :   variable_context.add_context_variables(variables, data_typechecker);
     324             :   process::detail::action_context action_context;
     325             :   action_context.add_context_action_labels(actions, data_typechecker);
     326             :   regular_formula result;
     327             :   detail::make_typecheck_builder(data_typechecker, variable_context, action_context).
     328             :            apply(result, regular_formulas::normalize_sorts(x, data_typechecker.typechecked_data_specification()));
     329             :   return result;
     330             : }
     331             : 
     332             : inline
     333             : regular_formula typecheck_regular_formula(const regular_formula& x, const lps::stochastic_specification& lpsspec)
     334             : {
     335             :   return typecheck_regular_formula(x, lpsspec.data(), lpsspec.global_variables(), lpsspec.action_labels());
     336             : }
     337             : 
     338             : } // namespace regular_formulas
     339             : 
     340             : namespace state_formulas
     341             : {
     342             : 
     343             : namespace detail
     344             : {
     345             : 
     346             : struct typecheck_builder: public state_formula_builder<typecheck_builder>
     347             : {
     348             :   typedef state_formula_builder<typecheck_builder> super;
     349             :   using super::apply;
     350             : 
     351             :   data::data_type_checker& m_data_type_checker;
     352             :   data::detail::variable_context m_variable_context;
     353             :   const process::detail::action_context& m_action_context;
     354             :   detail::state_variable_context m_state_variable_context;
     355             :   const bool m_formula_is_quantitative;        // If true, allow real values, otherwise restrict to a boolean formula.  
     356             : 
     357         179 :   typecheck_builder(data::data_type_checker& data_typechecker,
     358             :                     const data::detail::variable_context& variable_context,
     359             :                     const process::detail::action_context& action_context,
     360             :                     const detail::state_variable_context& state_variable_context,
     361             :                     const bool formula_is_quantitative
     362             :                    )
     363         179 :     : m_data_type_checker(data_typechecker),
     364         179 :       m_variable_context(variable_context),
     365         179 :       m_action_context(action_context),
     366         179 :       m_state_variable_context(state_variable_context),
     367         179 :       m_formula_is_quantitative(formula_is_quantitative)
     368         179 :   {}
     369             : 
     370             :   template <class T>
     371          26 :   void apply(T& result, const data::data_expression& x)
     372             :   {
     373          26 :     if (m_formula_is_quantitative)
     374             :     {
     375             :       try
     376             :       {
     377           1 :         result = m_data_type_checker.typecheck_data_expression(x, data::sort_real::real_(), m_variable_context);
     378             :       }
     379           0 :       catch (mcrl2::runtime_error& e1)
     380             :       {
     381             :         try 
     382             :         {
     383           0 :           result = m_data_type_checker.typecheck_data_expression(x, data::sort_bool::bool_(), m_variable_context);
     384             :         }
     385           0 :         catch (mcrl2::runtime_error& e2)
     386             :         {
     387           0 :           throw mcrl2::runtime_error("Fail to type data expression as bool or real: " + pp(x) + ".\n" +
     388           0 :                                      e1.what() + "\n" +
     389           0 :                                      e2.what());
     390             :         }
     391             :       }
     392             :     }
     393             :     else
     394             :     {
     395          25 :       result = m_data_type_checker.typecheck_data_expression(x, data::sort_bool::bool_(), m_variable_context);
     396             :     }
     397          26 :   }
     398             : 
     399             :   template <class T>
     400          19 :   void apply(T& result, const state_formulas::forall& x)
     401             :   {
     402          19 :     if (m_formula_is_quantitative)
     403             :     {
     404           0 :       throw mcrl2::runtime_error("Forall is not allowed to capture values in a quantitative modal formula " + state_formulas::pp(x) + ". Use inf for infimum instead. ");
     405             :     }
     406             :     else 
     407             :     {
     408             :       try
     409             :       {
     410          19 :         auto m_variable_context_copy = m_variable_context;
     411          19 :         m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     412          19 :         state_formula body;
     413          19 :         (*this).apply(body, x.body());
     414          19 :         m_variable_context = m_variable_context_copy;
     415          19 :         result = forall(x.variables(), body);
     416          19 :       }
     417           0 :       catch (mcrl2::runtime_error& e)
     418             :       {
     419           0 :         throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + state_formulas::pp(x));
     420             :       }
     421             :     }
     422          19 :   }
     423             : 
     424             :   template <class T>
     425           8 :   void apply(T& result, const state_formulas::exists& x)
     426             :   {
     427           8 :     if (m_formula_is_quantitative)
     428             :     {
     429           0 :       throw mcrl2::runtime_error("Exists is not allowed to capture values in a quantitative modal formula " + state_formulas::pp(x) + ". Use sup for supremum instead. ");
     430             :     }
     431             :     else 
     432             :     {
     433             :       try
     434             :       {
     435           8 :         auto m_variable_context_copy = m_variable_context;
     436           8 :         m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     437           8 :         state_formula body;
     438           8 :         (*this).apply(body, x.body());
     439           8 :         m_variable_context = m_variable_context_copy;
     440           8 :         result = exists(x.variables(), body);
     441           8 :       }
     442           0 :       catch (mcrl2::runtime_error& e)
     443             :       {
     444           0 :         throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + state_formulas::pp(x));
     445             :       }
     446             :     }
     447           8 :   }
     448             : 
     449             :   template <class T>
     450           2 :   void apply(T& result, const state_formulas::infimum& x)
     451             :   {
     452           2 :     if (!m_formula_is_quantitative)
     453             :     {
     454           0 :       throw mcrl2::runtime_error("Infimum is not allowed in an ordinary, non quantitative modal formula " + state_formulas::pp(x) + ". Use forall instead. ");
     455             :     }
     456             :     else 
     457             :     {
     458             :       try
     459             :       {
     460           2 :         auto m_variable_context_copy = m_variable_context;
     461           2 :         m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     462           2 :         state_formula body;
     463           2 :         (*this).apply(body, x.body());
     464           2 :         m_variable_context = m_variable_context_copy;
     465           2 :         result = infimum(x.variables(), body);
     466           2 :       }
     467           0 :       catch (mcrl2::runtime_error& e)
     468             :       {
     469           0 :         throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + state_formulas::pp(x));
     470             :       }
     471             :     }
     472           2 :   }
     473             : 
     474             :   template <class T>
     475           1 :   void apply(T& result, const state_formulas::supremum& x)
     476             :   {
     477           1 :     if (!m_formula_is_quantitative)
     478             :     {
     479           0 :       throw mcrl2::runtime_error("Supremum is not allowed in an ordinary, non quantitative modal formula " + state_formulas::pp(x) + ". Use exists instead. ");
     480             :     }
     481             :     else 
     482             :     {
     483             :       try
     484             :       {
     485           1 :         auto m_variable_context_copy = m_variable_context;
     486           1 :         m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     487           1 :         state_formula body;
     488           1 :         (*this).apply(body, x.body());
     489           1 :         m_variable_context = m_variable_context_copy;
     490           1 :         result = supremum(x.variables(), body);
     491           1 :       }
     492           0 :       catch (mcrl2::runtime_error& e)
     493             :       {
     494           0 :         throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + state_formulas::pp(x));
     495             :       }
     496             :     }
     497           1 :   }
     498             : 
     499             :   template <class T>
     500           1 :   void apply(T& result, const state_formulas::sum& x)
     501             :   {
     502           1 :     if (!m_formula_is_quantitative)
     503             :     {
     504           0 :       throw mcrl2::runtime_error("Sum is not allowed in an ordinary, non quantitative modal formula " + state_formulas::pp(x) + ". ");
     505             :     }
     506             :     else
     507             :     {
     508             :       try
     509             :       {
     510           1 :         auto m_variable_context_copy = m_variable_context;
     511           1 :         m_variable_context.add_context_variables(x.variables(), m_data_type_checker);
     512           1 :         state_formula body;
     513           1 :         (*this).apply(body, x.body());
     514           1 :         m_variable_context = m_variable_context_copy;
     515           1 :         result = sum(x.variables(), body);
     516           1 :       }
     517           0 :       catch (mcrl2::runtime_error& e)
     518             :       {
     519           0 :         throw mcrl2::runtime_error(std::string(e.what()) + "\nwhile typechecking " + state_formulas::pp(x));
     520             :       }
     521             :     }
     522           1 :   }
     523             : 
     524             :   template <class T>
     525          88 :   void apply(T& result, const state_formulas::may& x)
     526             :   {
     527          88 :     regular_formulas::regular_formula formula;
     528          88 :     regular_formulas::detail::make_typecheck_builder(m_data_type_checker, m_variable_context, m_action_context).apply(formula, x.formula());
     529          88 :     state_formula operand;
     530          88 :     (*this).apply(operand, x.operand());
     531          88 :     make_may(result, formula, operand);
     532          88 :   }
     533             : 
     534             :   template <class T>
     535         137 :   void apply(T& result, const state_formulas::must& x)
     536             :   {
     537         137 :     regular_formulas::regular_formula formula;
     538         137 :     regular_formulas::detail::make_typecheck_builder(m_data_type_checker, m_variable_context, m_action_context).apply(formula, x.formula());
     539         137 :     state_formula operand;
     540         137 :     (*this).apply(operand, x.operand());
     541         134 :     make_must(result, formula, operand);
     542         140 :   }
     543             : 
     544             :   template <class T>
     545           3 :   void apply(T& result, const state_formulas::delay_timed& x)
     546             :   {
     547           3 :     data::data_expression new_time = m_data_type_checker.typecheck_data_expression(x.time_stamp(), data::sort_real::real_(), m_variable_context);
     548           3 :     make_delay_timed(result, new_time);
     549           3 :   }
     550             : 
     551             :   template <class T>
     552           1 :   void apply(T& result, const state_formulas::yaled_timed& x)
     553             :   {
     554           1 :     data::data_expression new_time = m_data_type_checker.typecheck_data_expression(x.time_stamp(), data::sort_real::real_(), m_variable_context);
     555           1 :     make_yaled_timed(result, new_time);
     556           1 :   }
     557             : 
     558         143 :   state_formula apply_untyped_parameter(const core::identifier_string& name, const data::data_expression_list& arguments)
     559             :   {
     560         143 :     data::sort_expression_list expected_sorts = m_state_variable_context.matching_state_variable_sorts(name, arguments);
     561         142 :     data::data_expression_list new_arguments;
     562         142 :     auto q1 = expected_sorts.begin();
     563         142 :     auto q2 = arguments.begin();
     564         150 :     for (; q1 != expected_sorts.end(); ++q1, ++q2)
     565             :     {
     566           8 :       new_arguments.push_front(m_data_type_checker.typecheck_data_expression(*q2, *q1, m_variable_context));
     567             :     }
     568         142 :     new_arguments = atermpp::reverse(new_arguments);
     569         284 :     return state_formulas::variable(name, new_arguments);
     570         142 :   }
     571             : 
     572             :   template <class T>
     573           0 :   void apply(T& result, const state_formulas::variable& x)
     574             :   {
     575           0 :     result = apply_untyped_parameter(x.name(), x.arguments());
     576           0 :   }
     577             : 
     578             :   template <class T>
     579         143 :   void apply(T& result, const data::untyped_data_parameter& x)
     580             :   {
     581         143 :     result = apply_untyped_parameter(x.name(), x.arguments());
     582         142 :   }
     583             : 
     584         168 :   data::variable_list assignment_variables(const data::assignment_list& x) const
     585             :   {
     586         168 :     std::vector<data::variable> result;
     587         183 :     for (const data::assignment& a: x)
     588             :     {
     589          15 :       result.push_back(a.lhs());
     590             :     }
     591         336 :     return data::variable_list(result.begin(), result.end());
     592         168 :   }
     593             : 
     594             :   template <typename MuNuFormula>
     595         168 :   state_formula apply_mu_nu(const MuNuFormula& x, bool is_mu)
     596             :   {
     597         168 :     data::assignment_list new_assignments = m_data_type_checker.typecheck_assignment_list(x.assignments(), m_variable_context);
     598             : 
     599             :     // add the assignment variables to the context
     600         168 :     auto m_variable_context_copy = m_variable_context;
     601         168 :     data::variable_list x_variables = assignment_variables(x.assignments());
     602         168 :     m_variable_context.add_context_variables(x_variables, m_data_type_checker);
     603             : 
     604             :     // add x to the state variable context
     605         168 :     auto m_state_variable_context_copy = m_state_variable_context;
     606         168 :     m_state_variable_context.add_state_variable(x.name(), x_variables, m_data_type_checker);
     607             : 
     608             :     // typecheck the operand
     609         168 :     state_formula new_operand;
     610         168 :     (*this).apply(new_operand, x.operand());
     611             : 
     612             :     // restore the context
     613         166 :     m_variable_context = m_variable_context_copy;
     614         166 :     m_state_variable_context = m_state_variable_context_copy;
     615             : 
     616         166 :     if (is_mu)
     617             :     {
     618          99 :       return mu(x.name(), new_assignments, new_operand);
     619             :     }
     620             :     else
     621             :     {
     622          67 :       return nu(x.name(), new_assignments, new_operand);
     623             :     }
     624         176 :   }
     625             : 
     626             :   template <class T>
     627          68 :   void apply(T& result, const state_formulas::nu& x)
     628             :   {
     629          68 :     result = apply_mu_nu(x, false);
     630          67 :   }
     631             : 
     632             :   template <class T>
     633         100 :   void apply(T& result, const state_formulas::mu& x)
     634             :   {
     635         100 :     result = apply_mu_nu(x, true);
     636          99 :   }
     637             : 
     638             :   template <class T>
     639          36 :   void apply(T& result, const state_formulas::not_& x)
     640             :   {
     641          36 :     if (m_formula_is_quantitative)
     642             :     {
     643           0 :       throw mcrl2::runtime_error("No ! allowed in a quantitative modal formula " + state_formulas::pp(x) + ".");
     644             :     }
     645             :     else
     646             :     {
     647          36 :       apply(result, static_cast<not_>(x).operand());
     648          36 :       make_not_(result, result);
     649             :     }
     650          36 :   }
     651             : 
     652             :   template <class T>
     653           0 :   void apply(T& result, const state_formulas::minus& x)
     654             :   {
     655           0 :     if (!m_formula_is_quantitative)
     656             :     {
     657           0 :       throw mcrl2::runtime_error("No unary minus (-) allowed in a boolean modal formula " + state_formulas::pp(x) + ".");
     658             :     }
     659             :     else
     660             :     {
     661           0 :       apply(result, static_cast<minus>(x).operand());
     662           0 :       make_minus(result, result);
     663             :     }
     664           0 :   }
     665             : 
     666             :   template <class T>
     667           0 :   void apply(T& result, const state_formulas::plus& x)
     668             :   {
     669           0 :     if (!m_formula_is_quantitative)
     670             :     {
     671           0 :       throw mcrl2::runtime_error("No addition (+) allowed in a boolean modal formula " + state_formulas::pp(x) + ".");
     672             :     }
     673             :     else
     674             :     {
     675           0 :       apply(result, static_cast<plus>(x).left());
     676           0 :       state_formula rhs;
     677           0 :       apply(rhs, static_cast<plus>(x).right());
     678           0 :       make_plus(result, result, rhs);
     679           0 :     }
     680           0 :   }
     681             : 
     682             :   template <class T>
     683           1 :   void apply(T& result, const state_formulas::const_multiply& x)
     684             :   {
     685           1 :     if (!m_formula_is_quantitative)
     686             :     {
     687           0 :       throw mcrl2::runtime_error("No multiplication with a constant allowed in a boolean modal formula " + state_formulas::pp(x) + ".");
     688             :     }
     689             :     else
     690             :     {
     691           1 :       data::data_expression constant = m_data_type_checker.typecheck_data_expression(static_cast<const_multiply>(x).left(), data::sort_real::real_(), m_variable_context);
     692           1 :       state_formula rhs;
     693           1 :       apply(rhs, static_cast<const_multiply>(x).right());
     694           1 :       make_const_multiply(result, constant, rhs);
     695           1 :     }
     696           1 :   }
     697             : 
     698             :   template <class T>
     699           1 :   void apply(T& result, const state_formulas::const_multiply_alt& x)
     700             :   {
     701           1 :     if (!m_formula_is_quantitative)
     702             :     {
     703           0 :       throw mcrl2::runtime_error("No multiplication with a constant allowed in a boolean modal formula " + state_formulas::pp(x) + ".");
     704             :     }
     705             :     else
     706             :     {
     707           1 :       state_formula lhs;
     708           1 :       apply(lhs, static_cast<const_multiply_alt>(x).left());
     709           1 :       data::data_expression constant = m_data_type_checker.typecheck_data_expression(static_cast<const_multiply_alt>(x).right(), data::sort_real::real_(), m_variable_context);
     710           1 :       make_const_multiply_alt(result, lhs, constant);
     711           1 :     }
     712           1 :   }
     713             : };
     714             : 
     715             : inline
     716         179 : typecheck_builder make_typecheck_builder(
     717             :                     data::data_type_checker& data_typechecker,
     718             :                     const data::detail::variable_context& variable_context,
     719             :                     const process::detail::action_context& action_context,
     720             :                     const detail::state_variable_context& state_variable_context,
     721             :                     const bool formula_is_quantitative
     722             :                    )
     723             : {
     724         179 :   return typecheck_builder(data_typechecker, variable_context, action_context, state_variable_context, formula_is_quantitative);
     725             : }
     726             : 
     727             : } // namespace detail
     728             : 
     729             : class state_formula_type_checker
     730             : {
     731             :   protected:
     732             :     data::data_type_checker m_data_type_checker;
     733             :     data::detail::variable_context m_variable_context;
     734             :     process::detail::action_context m_action_context;
     735             :     detail::state_variable_context m_state_variable_context;
     736             :     const bool m_formula_is_quantitative;
     737             : 
     738             :   public:
     739             :     /** \brief     Constructor for a state_formula type checker.
     740             :      *  \param[in] dataspec The data specification against which state formulas are checked.
     741             :      *  \param[in] action_labels The data labels that can occur in a state formula.
     742             :      *  \param[in] variables A container containing variables that can occur in state formulas.
     743             :      **/
     744             :     template <typename ActionLabelContainer = std::vector<state_formulas::variable>, typename VariableContainer = std::vector<data::variable> >
     745         179 :     state_formula_type_checker(const data::data_specification& dataspec,
     746             :                                const bool formula_is_quantitative,
     747             :                                const ActionLabelContainer& action_labels = ActionLabelContainer(),
     748             :                                const VariableContainer& variables = VariableContainer()
     749             :                               )
     750         179 :       : m_data_type_checker(dataspec),
     751         179 :         m_formula_is_quantitative(formula_is_quantitative)
     752             :     {
     753         179 :       m_variable_context.add_context_variables(variables, m_data_type_checker);
     754         179 :       m_action_context.add_context_action_labels(action_labels, m_data_type_checker);
     755         179 :     }
     756             : 
     757             :     //check correctness of the state formula as follows:
     758             :     //1) determine the types of actions according to the definitions
     759             :     //   in spec
     760             :     //2) determine the types of data expressions according to the
     761             :     //   definitions in spec
     762             :     //3) check for name conflicts of data variable declarations in
     763             :     //   forall, exists, mu and nu quantifiers
     764             :     //4) check for monotonicity of fixpoint variables
     765         179 :     state_formula typecheck_state_formula(const state_formula& x)
     766             :     {
     767         179 :       mCRL2log(log::verbose) << "type checking state formula..." << std::endl;
     768         179 :       state_formula result;
     769         181 :       detail::make_typecheck_builder(m_data_type_checker, m_variable_context, m_action_context, m_state_variable_context, m_formula_is_quantitative).
     770         180 :                apply(result, state_formulas::normalize_sorts(x, m_data_type_checker.typechecked_data_specification()));
     771         178 :       return result;
     772           1 :     }
     773             : };
     774             : 
     775             : /** \brief     Type check a state formula.
     776             :  *  Throws an exception if something went wrong.
     777             :  *  \param[in] x A state formula that has not been type checked.
     778             :  *  \param[in] dataspec The data specification against which the formulas is checked.
     779             :  *  \param[in] action_labels A declaration of action labels that can be used in the state formulas.
     780             :  *  \param[in] variables A container with global data variables.
     781             :  *  \post      formula is type checked.
     782             :  **/
     783             : template <typename VariableContainer, typename ActionLabelContainer>
     784         179 : state_formula typecheck_state_formula(const state_formula& x,
     785             :                                       const bool formula_is_quantitative,
     786             :                                       const data::data_specification& dataspec = data::data_specification(),
     787             :                                       const ActionLabelContainer& action_labels = ActionLabelContainer(),
     788             :                                       const VariableContainer& variables = VariableContainer()
     789             :                                      )
     790             : {
     791             :   try
     792             :   {
     793         179 :     state_formula_type_checker type_checker(dataspec, formula_is_quantitative, action_labels, variables);
     794         357 :     return type_checker.typecheck_state_formula(x);
     795         179 :   }
     796           2 :   catch (mcrl2::runtime_error& e)
     797             :   {
     798           1 :     throw mcrl2::runtime_error(std::string(e.what()) + "\ncould not type check modal formula " + state_formulas::pp(x));
     799             :   }
     800             : }
     801             : 
     802             : /** \brief     Type check a state formula.
     803             :  *  Throws an exception if something went wrong.
     804             :  *  \param[in] x A state formula that has not been type checked.
     805             :  *  \param[in] lpsspec A linear process specifications containing data, action and global variable declarations
     806             :  *                     to be used when typechecking the formula.
     807             :  *  \post      formula is type checked.
     808             :  **/
     809             : inline
     810         174 : state_formula typecheck_state_formula(const state_formula& x,
     811             :                                       const lps::stochastic_specification& lpsspec,
     812             :                                       const bool formula_is_quantitative
     813             :                                      )
     814             : {
     815         174 :   return typecheck_state_formula(x, formula_is_quantitative, lpsspec.data(), lpsspec.action_labels(), lpsspec.global_variables());
     816             : }
     817             : 
     818             : /// \brief Typecheck the state formula specification formspec. It is assumed that the formula is self contained,
     819             : /// i.e. all actions and sorts must be declared.
     820             : inline
     821             : void typecheck_state_formula_specification(state_formula_specification& formspec, const bool formula_is_quantitative)
     822             : {
     823             :   try
     824             :   {
     825             :     data::data_type_checker checker(formspec.data());
     826             :     data::data_specification dataspec = checker.typechecked_data_specification();
     827             :     state_formulas::normalize_sorts(formspec, dataspec);
     828             :     state_formula_type_checker type_checker(dataspec, formula_is_quantitative, formspec.action_labels(), std::vector<data::variable>());
     829             :     formspec.formula() = type_checker.typecheck_state_formula(formspec.formula());
     830             :     formspec.data() = checker.typechecked_data_specification();
     831             :     formspec.data().translate_user_notation();
     832             :   }
     833             :   catch (mcrl2::runtime_error& e)
     834             :   {
     835             :     throw mcrl2::runtime_error(std::string(e.what()) + "\ncould not type check modal formula specification " + state_formulas::pp(formspec));
     836             :   }
     837             : }
     838             : 
     839             : /// \brief Typecheck the state formula specification formspec. It is assumed that the formula is not self contained,
     840             : /// i.e. some of the actions and sorts may be declared in lpsspec.
     841             : inline
     842             : void typecheck_state_formula_specification(state_formula_specification& formspec, const lps::stochastic_specification& lpsspec, const bool formula_is_quantitative)
     843             : {
     844             :   try
     845             :   {
     846             :     data::data_type_checker checker(formspec.data());
     847             :     data::data_specification dataspec = checker.typechecked_data_specification();
     848             :     state_formulas::normalize_sorts(formspec, dataspec);
     849             :     state_formula_type_checker type_checker(dataspec, formula_is_quantitative, lpsspec.action_labels() + formspec.action_labels(), lpsspec.global_variables());
     850             :     formspec.formula() = type_checker.typecheck_state_formula(formspec.formula());
     851             :     formspec.data() = checker.typechecked_data_specification();
     852             :     formspec.data().translate_user_notation();
     853             :   }
     854             :   catch (mcrl2::runtime_error& e)
     855             :   {
     856             :     throw mcrl2::runtime_error(std::string(e.what()) + "\ncould not type check modal formula specification " + state_formulas::pp(formspec));
     857             :   }
     858             : }
     859             : 
     860             : } // namespace state_formulas
     861             : 
     862             : } // namespace mcrl2
     863             : 
     864             : #endif // MCRL2_MODAL_FORMULA_TYPECHECK_H

Generated by: LCOV version 1.14