mCRL2
Loading...
Searching...
No Matches
sort_type_checker.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink, Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
11
12#ifndef MCRL2_DATA_SORT_TYPE_CHECKER_H
13#define MCRL2_DATA_SORT_TYPE_CHECKER_H
14
15#include "mcrl2/data/find.h"
17
18namespace mcrl2
19{
20
21namespace data
22{
23
25{
26 protected:
27 sort_specification m_sort_specification; // Intentionally a copy. If this is a reference or pointer the
28 // object to which this referred may disappear.
29
30 public:
32 sort_type_checker(const sort_specification& sort_spec, bool must_check_aliases = true)
33 : m_sort_specification(sort_spec)
34 {
36 if (must_check_aliases)
37 {
39 }
40 }
41
43 {
45 }
46
51 void operator()(const sort_expression& x) const
52 {
54 }
55
56 protected:
57 // Throws a runtime_error if a rewriting loop is detected via
58 // basic sorts, function sorts or sort containers.
60 const data::basic_sort& lhs,
61 const data::sort_expression& rhs,
62 std::set<basic_sort> sort_already_seen,
63 const std::map < basic_sort, sort_expression >& alias_map)
64 {
65 if (data::is_basic_sort(rhs))
66 {
67 const basic_sort& sort=atermpp::down_cast<basic_sort>(rhs);
68 if (sort == lhs)
69 {
70 throw mcrl2::runtime_error("Sort alias " + data::pp(lhs) + " is circularly defined.\n");
71 }
72 if (sort_already_seen.insert(sort).second && alias_map.count(sort)>0) // sort is newly added and there is an alias for this sort.
73 {
74 check_alias_circularity(lhs,alias_map.at(sort),sort_already_seen, alias_map);
75 }
76 sort_already_seen.erase(sort);
77 return;
78 }
80 {
81 const container_sort& c=atermpp::down_cast<container_sort>(rhs);
82 check_alias_circularity(lhs,c.element_sort(),sort_already_seen, alias_map);
83 return;
84 }
86 {
87 const function_sort& sort=atermpp::down_cast<function_sort>(rhs);
88 for(const sort_expression& s: sort.domain())
89 {
90 check_alias_circularity(lhs,s,sort_already_seen, alias_map);
91 }
92 check_alias_circularity(lhs,sort.codomain(),sort_already_seen, alias_map);
93 return;
94 }
95 // Intentionally no further search is done through a structured sort, because aliases
96 // can be circularly defined through structured sorts. Example: sort Tree = struct leaf | node(Tree,Tree);
97 assert(is_structured_sort(rhs));
98 }
99
101 {
102 // Check for double occurrences of sorts, as well as overlap with the five predefined basic sorts.
103 std::set<basic_sort> defined_sorts={ sort_pos::pos(), sort_nat::nat(), sort_int::int_(), sort_real::real_() };
105 {
106 if (!defined_sorts.insert(sort).second) // Sort did already exist.
107 {
108 throw mcrl2::runtime_error("Attempt to redeclare sort " + core::pp(sort.name()));
109 }
110 }
112 {
113 if (!defined_sorts.insert(a.name()).second) // Sort did already exist.
114 {
115 throw mcrl2::runtime_error("Attempt to redeclare sort in alias " + data::pp(a));
116 }
117 }
118 }
119
120
121 // Throws an exception if there is a problem with the alias
123 {
124 std::map < basic_sort, sort_expression > alias_map;
126 {
127 alias_map[a.name()]=a.reference();
128 }
129
130 std::set<data::basic_sort> sort_already_seen;
132 {
133 check_for_sort_alias_loop_through_function_sort(a.name(),a.reference(), sort_already_seen, false, alias_map);
134 assert(sort_already_seen.size()==0);
135 check_alias_circularity(a.name(), a.reference(),sort_already_seen, alias_map);
136 assert(sort_already_seen.size()==0);
137 }
138
139 try
140 {
142 {
143 (*this)(a.reference()); // Type check sort expression.
144 }
145 }
146 catch (mcrl2::runtime_error& e)
147 {
148 throw mcrl2::runtime_error(std::string(e.what()) + "\ntype checking of aliases failed");
149 }
150 }
151
153 const basic_sort& end_search,
154 const sort_expression& start_search,
155 std::set < basic_sort >& visited,
156 const bool observed_a_sort_constructor,
157 const std::map < basic_sort, sort_expression >& alias_map)
158 {
159 if (is_basic_sort(start_search))
160 {
161 const basic_sort& s=atermpp::down_cast<basic_sort>(start_search);
162 if (s==end_search)
163 {
164 // We found a loop.
165 if (observed_a_sort_constructor)
166 {
167 throw mcrl2::runtime_error("sort " + data::pp(end_search) + " is recursively defined via a function sort, or a set or a bag type container");
168 }
169 }
170
171 if (alias_map.count(s)==0 || visited.count(s)>0)
172 {
173 // start_search is not a sort alias, and hence not a recursive sort, or we have already seen sort s.
174 return;
175 }
176 visited.insert(s);
177 check_for_sort_alias_loop_through_function_sort(end_search,alias_map.at(s),visited,observed_a_sort_constructor,alias_map);
178 visited.erase(s);
179 return;
180 }
181
182 if (is_container_sort(start_search))
183 {
184 // A loop through a list container is allowed, but a loop through a set or bag container
185 // is problematic.
186 const container_sort& start_search_container=atermpp::down_cast<container_sort>(start_search);
188 end_search,
189 start_search_container.element_sort(),
190 visited,
191 start_search_container.container_name()==set_container()||start_search_container.container_name()==bag_container(),
192 alias_map);
193 return;
194 }
195
196 if (is_function_sort(start_search))
197 {
198 const function_sort& f_start_search=atermpp::down_cast<function_sort>(start_search);
199 check_for_sort_alias_loop_through_function_sort(end_search,f_start_search.codomain(),visited,true,alias_map);
200 for(const sort_expression& s: f_start_search.domain())
201 {
202 check_for_sort_alias_loop_through_function_sort(end_search,s,visited,true,alias_map);
203 }
204 // end_search has not been found, so:
205 return;
206 }
207
208 assert(is_structured_sort(start_search));
209
210 const structured_sort& struct_start_search=atermpp::down_cast<structured_sort>(start_search);
211 for(const function_symbol& f: struct_start_search.constructor_functions())
212 {
213 if (is_function_sort(f.sort()))
214 {
215 const sort_expression_list domain_sorts=function_sort(f.sort()).domain();
216 for(const sort_expression& s: domain_sorts)
217 {
218 check_for_sort_alias_loop_through_function_sort(end_search,s,visited,observed_a_sort_constructor,alias_map);
219 }
220 }
221 }
222 }
223
224
225 // Throws an exception if the sort x is not declared
227 {
228 if (sort_bool::is_bool(x) ||
229 sort_pos::is_pos(x) ||
230 sort_nat::is_nat(x) ||
231 sort_int::is_int(x) ||
233 {
234 return;
235 }
236 if (std::find(get_sort_specification().user_defined_sorts().begin(), get_sort_specification().user_defined_sorts().end(),x)!=
237 get_sort_specification().user_defined_sorts().end())
238 {
239 return;
240 }
242 {
243 if (x==a.name())
244 {
245 return;
246 }
247 }
248 throw mcrl2::runtime_error("basic or defined sort " + data::pp(x) + " is not declared");
249 }
250
251 void check_sort_list_is_declared(const sort_expression_list& SortExprList) const
252 {
253 for(const sort_expression& s: SortExprList)
254 {
256 }
257 }
258
260 {
261 if (is_basic_sort(x))
262 {
263 const basic_sort& bs = atermpp::down_cast<basic_sort>(x);
265 }
266 else if (is_container_sort(x))
267 {
268 const container_sort& cs = atermpp::down_cast<container_sort>(x);
270 }
271 else if (is_function_sort(x))
272 {
273 const function_sort& fs = atermpp::down_cast<function_sort>(x);
275 for(const sort_expression& s: fs.domain())
276 {
278 }
279 }
280 else if (is_structured_sort(x))
281 {
282 const structured_sort& ss = atermpp::down_cast<structured_sort>(x);
283 for(const structured_sort_constructor& constructor: ss.constructors())
284 {
285 for(const structured_sort_constructor_argument& arg: constructor.arguments())
286 {
288 }
289 }
290 }
291 else
292 {
293 throw mcrl2::runtime_error("this is not a sort expression " + data::pp(x));
294 }
295 }
296
298 {
299 std::set<sort_expression> possibly_empty_constructor_sorts;
300 for(const function_symbol& constructor: constructors)
301 {
302 const sort_expression& s = constructor.sort();
303 if (is_function_sort(s))
304 {
305 // if s is a constant sort, nothing needs to be added.
306 possibly_empty_constructor_sorts.insert(normalize_sorts(function_sort(s).codomain(),get_sort_specification()));
307 }
308 }
309
310 // Walk through the constructors removing constructor sorts that are not empty,
311 // until no more constructors sorts can be removed.
312 for(bool stable=false ; !stable ;)
313 {
314 stable=true;
315 for(const function_symbol& constructor: constructors)
316 {
317 const sort_expression& s = constructor.sort();
318 if (!is_function_sort(s))
319 {
320 if (possibly_empty_constructor_sorts.erase(normalize_sorts(s,get_sort_specification()))==1) // True if one element has been removed.
321 {
322 stable=false;
323 }
324 }
325 else
326 {
327 bool has_a_domain_sort_possibly_empty_sorts=false;
328 for(const sort_expression& sort: static_cast<const function_sort&>(s).domain())
329 {
330 if (possibly_empty_constructor_sorts.find(normalize_sorts(sort, get_sort_specification()))!=possibly_empty_constructor_sorts.end())
331 {
332 //
333 has_a_domain_sort_possibly_empty_sorts=true;
334 continue;
335 }
336 }
337 if (!has_a_domain_sort_possibly_empty_sorts)
338 {
339 // Condition below is true if one element has been removed.
340 if (possibly_empty_constructor_sorts.erase(normalize_sorts(static_cast<const function_sort&>(s).codomain(),get_sort_specification()))==1)
341 {
342 stable=false;
343 }
344 }
345 }
346 }
347 }
348 // Print the sorts remaining in possibly_empty_constructor_sorts, as they must be empty
349 if (possibly_empty_constructor_sorts.empty())
350 {
351 return; // There are no empty sorts
352 }
353 else
354 {
355 std::string reason="the following domains are empty due to recursive constructors:";
356 for(const sort_expression& sort: possibly_empty_constructor_sorts)
357 {
358 reason = reason + "\n" + data::pp(sort);
359 }
360 throw mcrl2::runtime_error(reason);
361 }
362 }
363};
364
365} // namespace data
366
367} // namespace mcrl2
368
369#endif // MCRL2_DATA_SORT_TYPE_CHECKER_H
A list of aterm objects.
Definition aterm_list.h:24
\brief A sort alias
Definition alias.h:26
\brief Container type for bags
\brief A basic sort
Definition basic_sort.h:26
const core::identifier_string & name() const
Definition basic_sort.h:57
\brief A container sort
const container_type & container_name() const
const sort_expression & element_sort() const
sort_expression sort() const
Returns the sort of the data expression.
Definition data.cpp:108
\brief A function sort
const sort_expression & codomain() const
const sort_expression_list & domain() const
\brief A function symbol
const sort_expression & sort() const
\brief Container type for sets
\brief A sort expression
const basic_sort_vector & user_defined_sorts() const
Gets all sorts defined by a user (excluding the system defined sorts).
const alias_vector & user_defined_aliases() const
Gets the user defined aliases.
void check_for_sort_alias_loop_through_function_sort(const basic_sort &end_search, const sort_expression &start_search, std::set< basic_sort > &visited, const bool observed_a_sort_constructor, const std::map< basic_sort, sort_expression > &alias_map)
sort_specification m_sort_specification
const sort_specification & get_sort_specification() const
void check_sort_list_is_declared(const sort_expression_list &SortExprList) const
sort_type_checker(const sort_specification &sort_spec, bool must_check_aliases=true)
constructs a sort expression checker.
void operator()(const sort_expression &x) const
Type check a sort expression. Throws an exception if the expression is not well typed.
void check_basic_sort_is_declared(const basic_sort &x) const
void check_for_empty_constructor_domains(const function_symbol_vector &constructors)
void check_alias_circularity(const data::basic_sort &lhs, const data::sort_expression &rhs, std::set< basic_sort > sort_already_seen, const std::map< basic_sort, sort_expression > &alias_map)
void check_sort_is_declared(const sort_expression &x) const
\brief An argument of a constructor of a structured sort
\brief A constructor for a structured sort
function_symbol_vector constructor_functions(const sort_expression &s) const
const structured_sort_constructor_list & constructors() const
Standard exception class for reporting runtime errors.
Definition exception.h:27
Search functions of the data library.
std::string pp(const identifier_string &x)
Definition core.cpp:26
bool is_bool(const sort_expression &e)
Recogniser for sort expression Bool.
Definition bool.h:54
bool is_int(const sort_expression &e)
Recogniser for sort expression Int.
Definition int1.h:57
const basic_sort & int_()
Constructor for sort expression Int.
Definition int1.h:47
const basic_sort & nat()
Constructor for sort expression Nat.
Definition nat1.h:46
bool is_nat(const sort_expression &e)
Recogniser for sort expression Nat.
Definition nat1.h:56
bool is_pos(const sort_expression &e)
Recogniser for sort expression Pos.
Definition pos1.h:55
const basic_sort & pos()
Constructor for sort expression Pos.
Definition pos1.h:45
const basic_sort & real_()
Constructor for sort expression Real.
Definition real1.h:48
bool is_real(const sort_expression &e)
Recogniser for sort expression Real.
Definition real1.h:58
bool is_structured_sort(const atermpp::aterm &x)
Returns true if the term t is a structured sort.
std::string pp(const abstraction &x)
Definition data.cpp:39
bool is_container_sort(const atermpp::aterm &x)
Returns true if the term t is a container sort.
bool is_basic_sort(const atermpp::aterm &x)
Returns true if the term t is a basic sort.
bool is_function_sort(const atermpp::aterm &x)
Returns true if the term t is a function sort.
data_expression normalize_sorts(const data_expression &x, const data::sort_specification &sortspec)
Definition data.cpp:86
std::vector< function_symbol > function_symbol_vector
\brief vector of function_symbols
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
This file describes the a sort_specification,.