@@ -13,6 +13,12 @@ response_or_errort<smtt>::response_or_errort(std::string message)
1313{
1414}
1515
16+ template <class smtt >
17+ response_or_errort<smtt>::response_or_errort(std::vector<std::string> messages)
18+ : messages{std::move (messages)}
19+ {
20+ }
21+
1622template <class smtt >
1723const smtt *response_or_errort<smtt>::get_if_valid() const
1824{
@@ -35,6 +41,114 @@ const std::vector<std::string> *response_or_errort<smtt>::get_if_error() const
3541
3642template class response_or_errort <smt_responset>;
3743
44+ // Implementation detail of `collect_messages` below.
45+ template <typename argumentt, typename ... argumentst>
46+ void collect_messages_impl (
47+ std::vector<std::string> &collected_messages,
48+ argumentt &&argument)
49+ {
50+ if (const auto messages = argument.get_if_error ())
51+ {
52+ collected_messages.insert (
53+ collected_messages.end (), messages->cbegin (), messages->end ());
54+ }
55+ }
56+
57+ // Implementation detail of `collect_messages` below.
58+ template <typename argumentt, typename ... argumentst>
59+ void collect_messages_impl (
60+ std::vector<std::string> &collected_messages,
61+ argumentt &&argument,
62+ argumentst &&... arguments)
63+ {
64+ collect_messages_impl (collected_messages, argument);
65+ collect_messages_impl (collected_messages, arguments...);
66+ }
67+
68+ // / Builds a collection of messages composed all messages in the
69+ // / `response_or_errort` typed arguments in \p arguments. This is a templated
70+ // / function in order to handle `response_or_errort` instances which are
71+ // / specialised differently.
72+ template <typename ... argumentst>
73+ std::vector<std::string> collect_messages (argumentst &&... arguments)
74+ {
75+ std::vector<std::string> collected_messages;
76+ collect_messages_impl (collected_messages, arguments...);
77+ return collected_messages;
78+ }
79+
80+ // / \brief Given a class to construct and a set of arguments to its constructor
81+ // / which may include errors, either return the collected errors if there are
82+ // / any or construct the class otherwise.
83+ // / \tparam smt_to_constructt
84+ // / The class to construct.
85+ // / \tparam smt_baset
86+ // / If the class to construct should be upcast to a base class before being
87+ // / stored in the `response_or_errort`, then the base class should be supplied
88+ // / in this parameter. If no upcast is required, then this should be left
89+ // / empty.
90+ // / \tparam argumentst
91+ // / The pack of argument types matching the constructor of
92+ // / `smt_to_constructt`. These must each be packed into an instance of
93+ // / `response_or_errort`.
94+ template <
95+ typename smt_to_constructt,
96+ typename smt_baset = smt_to_constructt,
97+ typename ... argumentst>
98+ response_or_errort<smt_baset> validation_propagating (argumentst &&... arguments)
99+ {
100+ const auto collected_messages = collect_messages (arguments...);
101+ if (!collected_messages.empty ())
102+ return response_or_errort<smt_baset>(collected_messages);
103+ else
104+ {
105+ return response_or_errort<smt_baset>{
106+ smt_to_constructt{(*arguments.get_if_valid ())...}};
107+ }
108+ }
109+
110+ static response_or_errort<irep_idt>
111+ validate_string_literal (const irept &parse_tree)
112+ {
113+ if (!parse_tree.get_sub ().empty ())
114+ {
115+ return response_or_errort<irep_idt>(
116+ " Expected string literal, found \" " + parse_tree.pretty (0 , 0 ) + " \" ." );
117+ }
118+ return response_or_errort<irep_idt>{parse_tree.id ()};
119+ }
120+
121+ // / \returns: A response or error in the case where the parse tree appears to be
122+ // / a get-value command. Returns empty otherwise.
123+ // / \note: Because this kind of response does not start with an identifying
124+ // / keyword, it will be considered that the response is intended to be a
125+ // / get-value response if it is composed of a collection of one or more pairs.
126+ static optionalt<response_or_errort<smt_responset>>
127+ valid_smt_error_response (const irept &parse_tree)
128+ {
129+ // Check if the parse tree looks to be an error response.
130+ if (!parse_tree.id ().empty ())
131+ return {};
132+ if (parse_tree.get_sub ().empty ())
133+ return {};
134+ if (parse_tree.get_sub ().at (0 ).id () != " error" )
135+ return {};
136+ // Parse tree is now considered to be an error response and anything
137+ // unexpected in the parse tree is now considered to be an invalid response.
138+ if (parse_tree.get_sub ().size () == 1 )
139+ {
140+ return {response_or_errort<smt_responset>{
141+ " Error response is missing the error message." }};
142+ }
143+ if (parse_tree.get_sub ().size () > 2 )
144+ {
145+ return {response_or_errort<smt_responset>{
146+ " Error response has multiple error messages." }};
147+ }
148+ return validation_propagating<smt_error_responset, smt_responset>(
149+ validate_string_literal (parse_tree.get_sub ()[1 ]));
150+ }
151+
38152response_or_errort<smt_responset> validate_smt_response (const irept &parse_tree)
39153{
40154 if (parse_tree.id () == " sat" )
@@ -46,6 +160,8 @@ response_or_errort<smt_responset> validate_smt_response(const irept &parse_tree)
46160 if (parse_tree.id () == " unknown" )
47161 return response_or_errort<smt_responset>{
48162 smt_check_sat_responset{smt_unknown_responset{}}};
163+ if (const auto error_response = valid_smt_error_response (parse_tree))
164+ return *error_response;
49165 if (parse_tree.id () == " success" )
50166 return response_or_errort<smt_responset>{smt_success_responset{}};
51167 if (parse_tree.id () == " unsupported" )
0 commit comments