Skip to content

Commit 30e5339

Browse files
authored
Merge pull request #3726 from danpoe/fixes/json-symbol-table
Make JSON symbol table input and output consistent
2 parents ffe2e58 + a3f38e7 commit 30e5339

11 files changed

+333
-61
lines changed

src/goto-programs/show_symbol_table.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ static void show_symbol_table_json_ui(
196196

197197
json_objectt symbol_json(
198198
{{"prettyName", json_stringt(symbol.pretty_name)},
199+
{"name", json_stringt(symbol.name)},
199200
{"baseName", json_stringt(symbol.base_name)},
200201
{"mode", json_stringt(symbol.mode)},
201202
{"module", json_stringt(symbol.module)},

src/json-symtab-language/json_symbol.cpp

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -69,44 +69,50 @@ symbolt symbol_from_json(const jsont &in)
6969
result.name = try_get_string(kv.second, "name");
7070
else if(kv.first == "module")
7171
result.module = try_get_string(kv.second, "module");
72-
else if(kv.first == "base_name")
73-
result.base_name = try_get_string(kv.second, "base_name");
72+
else if(kv.first == "baseName")
73+
result.base_name = try_get_string(kv.second, "baseName");
7474
else if(kv.first == "mode")
7575
result.mode = try_get_string(kv.second, "mode");
76-
else if(kv.first == "pretty_name")
77-
result.pretty_name = try_get_string(kv.second, "pretty_name");
78-
else if(kv.first == "is_type")
79-
result.is_type = try_get_bool(kv.second, "is_type");
80-
else if(kv.first == "is_macro")
81-
result.is_macro = try_get_bool(kv.second, "is_macro");
82-
else if(kv.first == "is_exported")
83-
result.is_exported = try_get_bool(kv.second, "is_exported");
84-
else if(kv.first == "is_input")
85-
result.is_input = try_get_bool(kv.second, "is_input");
86-
else if(kv.first == "is_output")
87-
result.is_output = try_get_bool(kv.second, "is_output");
88-
else if(kv.first == "is_state_var")
89-
result.is_state_var = try_get_bool(kv.second, "is_state_var");
90-
else if(kv.first == "is_property")
91-
result.is_property = try_get_bool(kv.second, "is_property");
92-
else if(kv.first == "is_static_lifetime")
93-
result.is_static_lifetime = try_get_bool(kv.second, "is_static_lifetime");
94-
else if(kv.first == "is_thread_local")
95-
result.is_thread_local = try_get_bool(kv.second, "is_thread_local");
96-
else if(kv.first == "is_lvalue")
97-
result.is_lvalue = try_get_bool(kv.second, "is_lvalue");
98-
else if(kv.first == "is_file_local")
99-
result.is_file_local = try_get_bool(kv.second, "is_file_local");
100-
else if(kv.first == "is_extern")
101-
result.is_extern = try_get_bool(kv.second, "is_extern");
102-
else if(kv.first == "is_volatile")
103-
result.is_volatile = try_get_bool(kv.second, "is_volatile");
104-
else if(kv.first == "is_parameter")
105-
result.is_parameter = try_get_bool(kv.second, "is_parameter");
106-
else if(kv.first == "is_auxiliary")
107-
result.is_auxiliary = try_get_bool(kv.second, "is_auxiliary");
108-
else if(kv.first == "is_weak")
109-
result.is_weak = try_get_bool(kv.second, "is_weak");
76+
else if(kv.first == "prettyName")
77+
result.pretty_name = try_get_string(kv.second, "prettyName");
78+
else if(kv.first == "isType")
79+
result.is_type = try_get_bool(kv.second, "isType");
80+
else if(kv.first == "isMacro")
81+
result.is_macro = try_get_bool(kv.second, "isMacro");
82+
else if(kv.first == "isExported")
83+
result.is_exported = try_get_bool(kv.second, "isExported");
84+
else if(kv.first == "isInput")
85+
result.is_input = try_get_bool(kv.second, "isInput");
86+
else if(kv.first == "isOutput")
87+
result.is_output = try_get_bool(kv.second, "isOutput");
88+
else if(kv.first == "isStateVar")
89+
result.is_state_var = try_get_bool(kv.second, "isStateVar");
90+
else if(kv.first == "isProperty")
91+
result.is_property = try_get_bool(kv.second, "isProperty");
92+
else if(kv.first == "isStaticLifetime")
93+
result.is_static_lifetime = try_get_bool(kv.second, "isStaticLifetime");
94+
else if(kv.first == "isThreadLocal")
95+
result.is_thread_local = try_get_bool(kv.second, "isThreadLocal");
96+
else if(kv.first == "isLvalue")
97+
result.is_lvalue = try_get_bool(kv.second, "isLvalue");
98+
else if(kv.first == "isFileLocal")
99+
result.is_file_local = try_get_bool(kv.second, "isFileLocal");
100+
else if(kv.first == "isExtern")
101+
result.is_extern = try_get_bool(kv.second, "isExtern");
102+
else if(kv.first == "isVolatile")
103+
result.is_volatile = try_get_bool(kv.second, "isVolatile");
104+
else if(kv.first == "isParameter")
105+
result.is_parameter = try_get_bool(kv.second, "isParameter");
106+
else if(kv.first == "isAuxiliary")
107+
result.is_auxiliary = try_get_bool(kv.second, "isAuxiliary");
108+
else if(kv.first == "isWeak")
109+
result.is_weak = try_get_bool(kv.second, "isWeak");
110+
else if(kv.first == "prettyType")
111+
{
112+
} // ignore
113+
else if(kv.first == "prettyValue")
114+
{
115+
} // ignore
110116
else
111117
throw deserialization_exceptiont(
112118
"symbol_from_json: unexpected key '" + kv.first + "'");

src/json-symtab-language/json_symbol_table.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,38 @@ Author: Chris Smowton, [email protected]
1515

1616
void symbol_table_from_json(const jsont &in, symbol_tablet &symbol_table)
1717
{
18-
if(!in.is_array())
18+
if(!in.is_object())
19+
{
20+
throw deserialization_exceptiont(
21+
"symbol_table_from_json: JSON input must be an object");
22+
}
23+
24+
const json_objectt &json_object = to_json_object(in);
25+
const auto it = json_object.find("symbolTable");
26+
27+
if(it == json_object.end())
28+
{
1929
throw deserialization_exceptiont(
20-
"symbol_table_from_json: JSON input must be an array");
21-
for(const auto &js_symbol : to_json_array(in))
30+
"symbol_table_from_json: JSON object must have key `symbolTable`");
31+
}
32+
33+
if(!it->second.is_object())
2234
{
23-
symbolt deserialized = symbol_from_json(js_symbol);
24-
if(symbol_table.add(deserialized))
35+
throw deserialization_exceptiont(
36+
"symbol_table_from_json: JSON symbol table must be an object");
37+
}
38+
39+
const json_objectt &json_symbol_table = to_json_object(it->second);
40+
41+
for(const auto &pair : json_symbol_table)
42+
{
43+
const jsont &json_symbol = pair.second;
44+
45+
symbolt symbol = symbol_from_json(json_symbol);
46+
47+
if(symbol_table.add(symbol))
2548
throw deserialization_exceptiont(
26-
"symbol_table_from_json: duplicate symbol name '" +
27-
id2string(deserialized.name) + "'");
49+
"symbol_table_from_json: duplicate symbol name `" +
50+
id2string(symbol.name) + "`");
2851
}
2952
}

src/util/json_irep.cpp

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ json_objectt json_irept::convert_from_irep(const irept &irep) const
3434
{
3535
json_objectt irep_object;
3636

37-
if(irep.id()!=ID_nil)
38-
irep_object["id"]=json_stringt(irep.id_string());
37+
irep_object["id"] = json_stringt(irep.id_string());
3938

4039
convert_sub_tree("sub", irep.get_sub(), irep_object);
4140
convert_named_sub_tree("namedSub", irep.get_named_sub(), irep_object);
@@ -97,27 +96,44 @@ void json_irept::convert_named_sub_tree(
9796
/// \return result - irep equivalent of input
9897
irept json_irept::convert_from_json(const jsont &in) const
9998
{
100-
std::vector<std::string> have_keys;
101-
for(const auto &keyval : to_json_object(in))
102-
have_keys.push_back(keyval.first);
103-
std::sort(have_keys.begin(), have_keys.end());
104-
if(have_keys!=std::vector<std::string>{"comment", "id", "namedSub", "sub"})
99+
if(!in.is_object())
105100
{
106101
throw deserialization_exceptiont(
107-
"irep JSON representation is missing one of needed keys: "
108-
"'id', 'sub', 'namedSub', 'comment'");
102+
"irep JSON representation must be an object");
109103
}
110104

111-
irept out(in["id"].value);
105+
const json_objectt &json_object = to_json_object(in);
112106

113-
for(const auto &sub : to_json_array(in["sub"]))
114-
out.get_sub().push_back(convert_from_json(sub));
107+
irept out;
115108

116-
for(const auto &named_sub : to_json_object(in["namedSub"]))
117-
out.add(named_sub.first)=convert_from_json(named_sub.second);
109+
{
110+
const auto it = json_object.find("id");
111+
112+
if(it != json_object.end())
113+
{
114+
out.id(it->second.value);
115+
}
116+
}
117+
118+
{
119+
const auto it = json_object.find("sub");
120+
121+
if(it != json_object.end())
122+
{
123+
for(const auto &sub : to_json_array(it->second))
124+
out.get_sub().push_back(convert_from_json(sub));
125+
}
126+
}
127+
128+
{
129+
const auto it = json_object.find("namedSub");
118130

119-
for(const auto &comment : to_json_object(in["comment"]))
120-
out.add(comment.first)=convert_from_json(comment.second);
131+
if(it != json_object.end())
132+
{
133+
for(const auto &named_sub : to_json_object(it->second))
134+
out.add(named_sub.first) = convert_from_json(named_sub.second);
135+
}
136+
}
121137

122138
return out;
123139
}

src/util/symbol.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,34 @@ bool symbolt::is_well_formed() const
144144

145145
return true;
146146
}
147+
148+
bool symbolt::operator==(const symbolt &other) const
149+
{
150+
// clang-format off
151+
return
152+
type == other.type &&
153+
value == other.value &&
154+
location == other.location &&
155+
name == other.name &&
156+
module == other.module &&
157+
base_name == other.base_name &&
158+
mode == other.mode &&
159+
pretty_name == other.pretty_name &&
160+
is_type == other.is_type &&
161+
is_macro == other.is_macro &&
162+
is_exported == other.is_exported &&
163+
is_input == other.is_input &&
164+
is_output == other.is_output &&
165+
is_state_var == other.is_state_var &&
166+
is_property == other.is_property &&
167+
is_parameter == other.is_parameter &&
168+
is_auxiliary == other.is_auxiliary &&
169+
is_weak == other.is_weak &&
170+
is_lvalue == other.is_lvalue &&
171+
is_static_lifetime == other.is_static_lifetime &&
172+
is_thread_local == other.is_thread_local &&
173+
is_file_local == other.is_file_local &&
174+
is_extern == other.is_extern &&
175+
is_volatile == other.is_volatile;
176+
// clang-format on
177+
}

src/util/symbol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ class symbolt
124124

125125
/// Check that a symbol is well formed.
126126
bool is_well_formed() const;
127+
128+
bool operator==(const symbolt &other) const;
127129
};
128130

129131
std::ostream &operator<<(std::ostream &out, const symbolt &symbol);

src/util/symbol_table.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <util/invariant.h>
77
#include <util/validate.h>
88

9+
#include <set>
10+
911
/// Move or copy a new symbol to the symbol table.
1012
/// \remarks This is a nicer interface than move and achieves the same
1113
/// result as both move and add.
@@ -219,3 +221,42 @@ void symbol_tablet::validate(const validation_modet vm) const
219221
"'");
220222
}
221223
}
224+
225+
bool symbol_tablet::operator==(const symbol_tablet &other) const
226+
{
227+
// we cannot use == for comparing the multimaps as it compares the items
228+
// sequentially, but the order of items with equal keys depends on the
229+
// insertion order
230+
231+
{
232+
std::vector<std::pair<irep_idt, irep_idt>> v1(
233+
internal_symbol_base_map.begin(), internal_symbol_base_map.end());
234+
235+
std::vector<std::pair<irep_idt, irep_idt>> v2(
236+
other.internal_symbol_base_map.begin(),
237+
other.internal_symbol_base_map.end());
238+
239+
std::sort(v1.begin(), v1.end());
240+
std::sort(v2.begin(), v2.end());
241+
242+
if(v1 != v2)
243+
return false;
244+
}
245+
246+
{
247+
std::vector<std::pair<irep_idt, irep_idt>> v1(
248+
internal_symbol_module_map.begin(), internal_symbol_module_map.end());
249+
250+
std::vector<std::pair<irep_idt, irep_idt>> v2(
251+
other.internal_symbol_module_map.begin(),
252+
other.internal_symbol_module_map.end());
253+
254+
std::sort(v1.begin(), v1.end());
255+
std::sort(v2.begin(), v2.end());
256+
257+
if(v1 != v2)
258+
return false;
259+
}
260+
261+
return internal_symbols == other.internal_symbols;
262+
}

src/util/symbol_table.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ class symbol_tablet : public symbol_table_baset
119119

120120
/// Check that the symbol table is well-formed
121121
void validate(const validation_modet vm = validation_modet::INVARIANT) const;
122+
123+
bool operator==(const symbol_tablet &other) const;
122124
};
123125

124126
#endif // CPROVER_UTIL_SYMBOL_TABLE_H

src/util/ui_message.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ class ui_message_handlert : public message_handlert
2727

2828
virtual ~ui_message_handlert();
2929

30-
uit get_ui() const
30+
virtual uit get_ui() const
3131
{
3232
return _ui;
3333
}
3434

3535
virtual void flush(unsigned level) override;
3636

37-
json_stream_arrayt &get_json_stream()
37+
virtual json_stream_arrayt &get_json_stream()
3838
{
3939
PRECONDITION(json_stream!=nullptr);
4040
return *json_stream;

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ SRC += analyses/ai/ai.cpp \
2828
goto-symex/ssa_equation.cpp \
2929
interpreter/interpreter.cpp \
3030
json/json_parser.cpp \
31+
json_symbol_table.cpp \
3132
path_strategies.cpp \
3233
pointer-analysis/value_set.cpp \
3334
solvers/floatbv/float_utils.cpp \

0 commit comments

Comments
 (0)