Skip to content

Commit 820294a

Browse files
committed
Add SMT get-value response validation for bool sorts
1 parent 460619b commit 820294a

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

src/solvers/smt2_incremental/smt_response_validation.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,88 @@ valid_smt_error_response(const irept &parse_tree)
176176
validate_string_literal(parse_tree.get_sub()[1]));
177177
}
178178

179+
static bool all_subs_are_pairs(const irept &parse_tree)
180+
{
181+
return std::all_of(
182+
parse_tree.get_sub().cbegin(),
183+
parse_tree.get_sub().cend(),
184+
[](const irept &sub) { return sub.get_sub().size() == 2; });
185+
}
186+
187+
static response_or_errort<irep_idt>
188+
validate_smt_identifier(const irept &parse_tree)
189+
{
190+
if(!parse_tree.get_sub().empty() || parse_tree.id().empty())
191+
{
192+
return response_or_errort<irep_idt>(
193+
"Expected identifier, found - \"" + print_parse_tree(parse_tree) + "\".");
194+
}
195+
return response_or_errort<irep_idt>(parse_tree.id());
196+
}
197+
198+
static optionalt<smt_termt> valid_smt_bool(const irept &parse_tree)
199+
{
200+
if(!parse_tree.get_sub().empty())
201+
return {};
202+
if(parse_tree.id() == ID_true)
203+
return {smt_bool_literal_termt{true}};
204+
if(parse_tree.id() == ID_false)
205+
return {smt_bool_literal_termt{false}};
206+
return {};
207+
}
208+
209+
static response_or_errort<smt_termt> validate_term(const irept &parse_tree)
210+
{
211+
if(const auto smt_bool = valid_smt_bool(parse_tree))
212+
return response_or_errort<smt_termt>{*smt_bool};
213+
return response_or_errort<smt_termt>{"Unrecognised SMT term - \"" +
214+
print_parse_tree(parse_tree) + "\"."};
215+
}
216+
217+
static response_or_errort<smt_get_value_responset::valuation_pairt>
218+
validate_valuation_pair(const irept &pair_parse_tree)
219+
{
220+
PRECONDITION(pair_parse_tree.get_sub().size() == 2);
221+
const auto &descriptor = pair_parse_tree.get_sub()[0];
222+
const auto &value = pair_parse_tree.get_sub()[1];
223+
return validation_propagating<smt_get_value_responset::valuation_pairt>(
224+
validate_smt_identifier(descriptor), validate_term(value));
225+
}
226+
227+
/// \returns: A response or error in the case where the parse tree appears to be
228+
/// a get-value command. Returns empty otherwise.
229+
/// \note: Because this kind of response does not start with an identifying
230+
/// keyword, it will be considered that the response is intended to be a
231+
/// get-value response if it is composed of a collection of one or more pairs.
232+
static optionalt<response_or_errort<smt_responset>>
233+
valid_smt_get_value_response(const irept &parse_tree)
234+
{
235+
// Shape matching for does this look like a get value response?
236+
if(!parse_tree.id().empty())
237+
return {};
238+
if(parse_tree.get_sub().empty())
239+
return {};
240+
if(!all_subs_are_pairs(parse_tree))
241+
return {};
242+
std::vector<std::string> error_messages;
243+
std::vector<smt_get_value_responset::valuation_pairt> valuation_pairs;
244+
for(const auto &pair : parse_tree.get_sub())
245+
{
246+
const auto pair_validation_result = validate_valuation_pair(pair);
247+
if(const auto error = pair_validation_result.get_if_error())
248+
error_messages.insert(error_messages.end(), error->begin(), error->end());
249+
if(const auto valid_pair = pair_validation_result.get_if_valid())
250+
valuation_pairs.push_back(*valid_pair);
251+
}
252+
if(!error_messages.empty())
253+
return {response_or_errort<smt_responset>{std::move(error_messages)}};
254+
else
255+
{
256+
return {response_or_errort<smt_responset>{
257+
smt_get_value_responset{valuation_pairs}}};
258+
}
259+
}
260+
179261
response_or_errort<smt_responset> validate_smt_response(const irept &parse_tree)
180262
{
181263
if(parse_tree.id() == "sat")
@@ -193,6 +275,8 @@ response_or_errort<smt_responset> validate_smt_response(const irept &parse_tree)
193275
return response_or_errort<smt_responset>{smt_success_responset{}};
194276
if(parse_tree.id() == "unsupported")
195277
return response_or_errort<smt_responset>{smt_unsupported_responset{}};
278+
if(const auto get_value_response = valid_smt_get_value_response(parse_tree))
279+
return *get_value_response;
196280
return response_or_errort<smt_responset>{"Invalid SMT response \"" +
197281
id2string(parse_tree.id()) + "\""};
198282
}

src/solvers/smt2_incremental/smt_responses.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,20 @@ smt_get_value_responset::valuation_pairt::valuation_pairt(
109109
smt_termt descriptor,
110110
smt_termt value)
111111
{
112+
INVARIANT(
113+
descriptor.get_sort() == value.get_sort(),
114+
"SMT valuation pair must have matching sort for the descriptor and value.");
112115
get_sub().push_back(upcast(std::move(descriptor)));
113116
get_sub().push_back(upcast(std::move(value)));
114117
}
115118

119+
smt_get_value_responset::valuation_pairt::valuation_pairt(
120+
irep_idt descriptor,
121+
const smt_termt &value)
122+
: valuation_pairt(smt_identifier_termt{descriptor, value.get_sort()}, value)
123+
{
124+
}
125+
116126
const smt_termt &smt_get_value_responset::valuation_pairt::descriptor() const
117127
{
118128
return downcast(get_sub().at(0));

src/solvers/smt2_incremental/smt_responses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class smt_get_value_responset
103103
public:
104104
valuation_pairt() = delete;
105105
valuation_pairt(smt_termt descriptor, smt_termt value);
106+
valuation_pairt(irep_idt descriptor, const smt_termt &value);
106107

107108
using irept::pretty;
108109

unit/solvers/smt2_incremental/smt_response_validation.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,24 @@ TEST_CASE("Validation of SMT error response", "[core][smt2_incremental]")
9191
.get_if_error() ==
9292
std::vector<std::string>{"Error response has multiple error messages."});
9393
}
94+
95+
TEST_CASE("smt get-value response validation", "[core][smt2_incremental]")
96+
{
97+
SECTION("Boolean sorted values.")
98+
{
99+
const response_or_errort<smt_responset> true_response =
100+
validate_smt_response(*smt2irep("((a true))").parsed_output);
101+
CHECK(
102+
*true_response.get_if_valid() ==
103+
smt_get_value_responset{{smt_get_value_responset::valuation_pairt{
104+
smt_identifier_termt{"a", smt_bool_sortt{}},
105+
smt_bool_literal_termt{true}}}});
106+
const response_or_errort<smt_responset> false_response =
107+
validate_smt_response(*smt2irep("((a false))").parsed_output);
108+
CHECK(
109+
*false_response.get_if_valid() ==
110+
smt_get_value_responset{{smt_get_value_responset::valuation_pairt{
111+
smt_identifier_termt{"a", smt_bool_sortt{}},
112+
smt_bool_literal_termt{false}}}});
113+
}
114+
}

0 commit comments

Comments
 (0)