Skip to content

Commit 7bdd7b8

Browse files
committed
copy language_file.cpp and language_file.h from CBMC
The logic implemented in CBMC's language_filest class typechecks modules starting from the leaves of the dependency tree. This is an ill-fit for both SMV and Verilog, which expect elaboration and type checking to start from the root (or "main") module. This copies the file that contains the langauge_filet and language_filest classes in order to make this change locally.
1 parent 3313643 commit 7bdd7b8

File tree

4 files changed

+472
-4
lines changed

4 files changed

+472
-4
lines changed

src/ebmc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SRC = \
1212
diatest.cpp \
1313
dimacs_writer.cpp \
1414
ebmc_base.cpp \
15+
ebmc_language_file.cpp \
1516
ebmc_languages.cpp \
1617
ebmc_parse_options.cpp \
1718
ebmc_properties.cpp \

src/ebmc/ebmc_language_file.cpp

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
/*******************************************************************\
2+
3+
Module:
4+
5+
Author: Daniel Kroening, kroening@kroening.com
6+
7+
\*******************************************************************/
8+
9+
#include "ebmc_language_file.h"
10+
11+
#include <util/message.h>
12+
13+
#include <langapi/language.h>
14+
15+
#include <fstream>
16+
17+
ebmc_language_filet::ebmc_language_filet(const ebmc_language_filet &rhs)
18+
: modules(rhs.modules),
19+
language(rhs.language == nullptr ? nullptr : rhs.language->new_language()),
20+
filename(rhs.filename)
21+
{
22+
}
23+
24+
/// To avoid compiler errors, the complete definition of a pointed-to type must
25+
/// be visible at the point at which the unique_ptr destructor is created. In
26+
/// this case, the pointed-to type is forward-declared, so we have to place the
27+
/// destructor in the source file, where the full definition is availible.
28+
ebmc_language_filet::~ebmc_language_filet() = default;
29+
30+
ebmc_language_filet::ebmc_language_filet(const std::string &filename)
31+
: filename(filename)
32+
{
33+
}
34+
35+
void ebmc_language_filet::get_modules()
36+
{
37+
language->modules_provided(modules);
38+
}
39+
40+
void ebmc_language_filet::convert_lazy_method(
41+
const irep_idt &id,
42+
symbol_table_baset &symbol_table,
43+
message_handlert &message_handler)
44+
{
45+
language->convert_lazy_method(id, symbol_table, message_handler);
46+
}
47+
48+
void ebmc_language_filest::show_parse(
49+
std::ostream &out,
50+
message_handlert &message_handler)
51+
{
52+
for(const auto &file : file_map)
53+
file.second.language->show_parse(out, message_handler);
54+
}
55+
56+
bool ebmc_language_filest::parse(message_handlert &message_handler)
57+
{
58+
messaget log(message_handler);
59+
60+
for(auto &file : file_map)
61+
{
62+
// open file
63+
64+
std::ifstream infile(file.first);
65+
66+
if(!infile)
67+
{
68+
log.error() << "Failed to open " << file.first << messaget::eom;
69+
return true;
70+
}
71+
72+
// parse it
73+
74+
languaget &language = *(file.second.language);
75+
76+
if(language.parse(infile, file.first, message_handler))
77+
{
78+
log.error() << "Parsing of " << file.first << " failed" << messaget::eom;
79+
return true;
80+
}
81+
82+
// what is provided?
83+
84+
file.second.get_modules();
85+
}
86+
87+
return false;
88+
}
89+
90+
bool ebmc_language_filest::typecheck(
91+
symbol_table_baset &symbol_table,
92+
const bool keep_file_local,
93+
message_handlert &message_handler)
94+
{
95+
// typecheck interfaces
96+
97+
for(auto &file : file_map)
98+
{
99+
if(file.second.language->interfaces(symbol_table, message_handler))
100+
return true;
101+
}
102+
103+
// build module map
104+
105+
unsigned collision_counter = 0;
106+
107+
for(auto &file : file_map)
108+
{
109+
const ebmc_language_filet::modulest &modules = file.second.modules;
110+
111+
for(ebmc_language_filet::modulest::const_iterator mo_it = modules.begin();
112+
mo_it != modules.end();
113+
mo_it++)
114+
{
115+
// these may collide, and then get renamed
116+
std::string module_name = *mo_it;
117+
118+
while(module_map.find(module_name) != module_map.end())
119+
{
120+
module_name = *mo_it + "#" + std::to_string(collision_counter);
121+
collision_counter++;
122+
}
123+
124+
ebmc_language_modulet module;
125+
module.file = &file.second;
126+
module.name = module_name;
127+
module_map.insert(
128+
std::pair<std::string, ebmc_language_modulet>(module.name, module));
129+
}
130+
}
131+
132+
// typecheck files
133+
134+
for(auto &file : file_map)
135+
{
136+
if(file.second.modules.empty())
137+
{
138+
if(file.second.language->can_keep_file_local())
139+
{
140+
if(file.second.language->typecheck(
141+
symbol_table, "", message_handler, keep_file_local))
142+
return true;
143+
}
144+
else
145+
{
146+
if(file.second.language->typecheck(symbol_table, "", message_handler))
147+
return true;
148+
}
149+
// register lazy methods.
150+
// TODO: learn about modules and generalise this
151+
// to module-providing languages if required.
152+
std::unordered_set<irep_idt> lazy_method_ids;
153+
file.second.language->methods_provided(lazy_method_ids);
154+
for(const auto &id : lazy_method_ids)
155+
lazy_method_map[id] = &file.second;
156+
}
157+
}
158+
159+
// typecheck modules
160+
161+
for(auto &module : module_map)
162+
{
163+
if(typecheck_module(
164+
symbol_table, module.second, keep_file_local, message_handler))
165+
return true;
166+
}
167+
168+
return false;
169+
}
170+
171+
bool ebmc_language_filest::generate_support_functions(
172+
symbol_table_baset &symbol_table,
173+
message_handlert &message_handler)
174+
{
175+
std::set<std::string> languages;
176+
177+
for(auto &file : file_map)
178+
{
179+
if(languages.insert(file.second.language->id()).second)
180+
if(file.second.language->generate_support_functions(
181+
symbol_table, message_handler))
182+
return true;
183+
}
184+
185+
return false;
186+
}
187+
188+
bool ebmc_language_filest::final(symbol_table_baset &symbol_table)
189+
{
190+
std::set<std::string> languages;
191+
192+
for(auto &file : file_map)
193+
{
194+
if(languages.insert(file.second.language->id()).second)
195+
if(file.second.language->final(symbol_table))
196+
return true;
197+
}
198+
199+
return false;
200+
}
201+
202+
bool ebmc_language_filest::interfaces(
203+
symbol_table_baset &symbol_table,
204+
message_handlert &message_handler)
205+
{
206+
for(auto &file : file_map)
207+
{
208+
if(file.second.language->interfaces(symbol_table, message_handler))
209+
return true;
210+
}
211+
212+
return false;
213+
}
214+
215+
bool ebmc_language_filest::typecheck_module(
216+
symbol_table_baset &symbol_table,
217+
const std::string &module,
218+
const bool keep_file_local,
219+
message_handlert &message_handler)
220+
{
221+
// check module map
222+
223+
module_mapt::iterator it = module_map.find(module);
224+
225+
if(it == module_map.end())
226+
{
227+
messaget log(message_handler);
228+
log.error() << "found no file that provides module " << module
229+
<< messaget::eom;
230+
return true;
231+
}
232+
233+
return typecheck_module(
234+
symbol_table, it->second, keep_file_local, message_handler);
235+
}
236+
237+
bool ebmc_language_filest::typecheck_module(
238+
symbol_table_baset &symbol_table,
239+
ebmc_language_modulet &module,
240+
const bool keep_file_local,
241+
message_handlert &message_handler)
242+
{
243+
// already typechecked?
244+
245+
if(module.type_checked)
246+
return false;
247+
248+
messaget log(message_handler);
249+
250+
// already in progress?
251+
252+
if(module.in_progress)
253+
{
254+
log.error() << "circular dependency in " << module.name << messaget::eom;
255+
return true;
256+
}
257+
258+
module.in_progress = true;
259+
260+
// first get dependencies of current module
261+
262+
std::set<std::string> dependency_set;
263+
264+
module.file->language->dependencies(module.name, dependency_set);
265+
266+
for(std::set<std::string>::const_iterator it = dependency_set.begin();
267+
it != dependency_set.end();
268+
it++)
269+
{
270+
module.in_progress =
271+
!typecheck_module(symbol_table, *it, keep_file_local, message_handler);
272+
if(module.in_progress == false)
273+
return true;
274+
}
275+
276+
// type check it
277+
278+
log.status() << "Type-checking " << module.name << messaget::eom;
279+
280+
if(module.file->language->can_keep_file_local())
281+
{
282+
module.in_progress = !module.file->language->typecheck(
283+
symbol_table, module.name, message_handler, keep_file_local);
284+
}
285+
else
286+
{
287+
module.in_progress = !module.file->language->typecheck(
288+
symbol_table, module.name, message_handler);
289+
}
290+
291+
if(!module.in_progress)
292+
return true;
293+
294+
module.type_checked = true;
295+
module.in_progress = false;
296+
297+
return false;
298+
}

0 commit comments

Comments
 (0)