ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
converter_internal.h
Go to the documentation of this file.
1#pragma once
2
7
8#include <nlohmann/json.hpp>
9
10#include <algorithm>
11#include <cctype>
12#include <optional>
13#include <string>
14#include <unordered_map>
15
17{
18// Python AST statement-id (e.g. "If", "Return") -> internal StatementType.
19inline StatementType get_statement_type(const nlohmann::json &element)
20{
21 static const std::unordered_map<std::string, StatementType> statement_map = {
22 {"AnnAssign", StatementType::VARIABLE_ASSIGN},
24 {"FunctionDef", StatementType::FUNC_DEFINITION},
26 {"AugAssign", StatementType::COMPOUND_ASSIGN},
29 {"Expr", StatementType::EXPR},
30 {"Return", StatementType::RETURN},
31 {"Assert", StatementType::ASSERT},
33 {"Pass", StatementType::PASS},
34 {"Break", StatementType::BREAK},
35 {"Continue", StatementType::CONTINUE},
36 {"ImportFrom", StatementType::IMPORT},
37 {"Import", StatementType::IMPORT},
38 {"Raise", StatementType::RAISE},
39 {"Global", StatementType::GLOBAL},
40 {"Nonlocal", StatementType::NONLOCAL},
41 {"Try", StatementType::TRY},
42 {"ExceptHandler", StatementType::EXCEPTHANDLER},
44
45 if (!element.contains("_type"))
47
48 auto it = statement_map.find(element["_type"]);
49 return (it != statement_map.end()) ? it->second : StatementType::UNKNOWN;
50}
51
52// Operator name (Python AST id, e.g. "Add", "Lt") -> ESBMC operator id.
53inline const std::unordered_map<std::string, std::string> &operator_map()
54{
55 static const std::unordered_map<std::string, std::string> m = {
56 {"add", "+"}, {"sub", "-"}, {"subtract", "-"},
57 {"mult", "*"}, {"multiply", "*"}, {"dot", "*"},
58 {"div", "/"}, {"divide", "/"}, {"mod", "mod"},
59 {"bitor", "bitor"}, {"floordiv", "/"}, {"bitand", "bitand"},
60 {"bitxor", "bitxor"}, {"invert", "bitnot"}, {"lshift", "shl"},
61 {"rshift", "ashr"}, {"usub", "unary-"}, {"eq", "="},
62 {"lt", "<"}, {"lte", "<="}, {"noteq", "notequal"},
63 {"gt", ">"}, {"gte", ">="}, {"and", "and"},
64 {"or", "or"}, {"not", "not"}, {"uadd", "unary+"},
65 {"is", "="}, {"isnot", "not"}, {"in", "="}};
66 return m;
67}
68
69// Map a Python operator name to its ESBMC representation. Uses IEEE-specific
70// operators when the type is floating-point.
71inline std::string map_operator(const std::string &op, const typet &type)
72{
73 // Convert the operator to lowercase to allow case-insensitive comparison.
74 std::string lower_op = op;
75 std::transform(
76 lower_op.begin(), lower_op.end(), lower_op.begin(), [](unsigned char c) {
77 return std::tolower(c);
78 });
79
80 // If the type is floating-point, use IEEE-specific operators.
81 if (type.is_floatbv())
82 {
83 static const std::unordered_map<std::string, std::string> float_ops = {
84 {"add", "ieee_add"},
85 {"sub", "ieee_sub"},
86 {"subtract", "ieee_sub"},
87 {"mult", "ieee_mul"},
88 {"dot", "ieee_mul"},
89 {"multiply", "ieee_mul"},
90 {"div", "ieee_div"},
91 {"divide", "ieee_div"}};
92
93 auto float_it = float_ops.find(lower_op);
94 if (float_it != float_ops.end())
95 return float_it->second;
96 }
97
98 // Look up the operator in the general operator map (for non-floating-point
99 // types).
100 const auto &m = operator_map();
101 auto it = m.find(lower_op);
102 if (it != m.end())
103 return it->second;
104
105 log_warning("Unknown operator: {}", op);
106 return {};
107}
108
109// Build a struct member component tagged for its owning class.
111 const std::string &class_name,
112 const std::string &comp_name,
113 const typet &type)
114{
115 struct_typet::componentt component(comp_name, comp_name, type);
116
117 // Add metadata used internally by ESBMC for member-to-class tagging.
118 // The key "#member_name" is used by the type system; the value
119 // "tag-<class_name>" helps associate this member with its parent class.
120 type_utils::set_member_name(component.type(), "tag-" + class_name);
121
122 // Set the member visibility to public by default.
123 component.set_access("public");
124
125 return component;
126}
127
128// Returns true if the named class inherits from Python's Enum.
129inline bool
130is_enum_class(const std::string &class_name, const nlohmann::json &ast_json)
131{
132 const nlohmann::json class_node =
133 json_utils::find_class(ast_json["body"], class_name);
134 if (
135 class_node.empty() || !class_node.contains("bases") ||
136 !class_node["bases"].is_array())
137 return false;
138 for (const auto &base : class_node["bases"])
139 if (base.is_object() && base.contains("id"))
140 {
141 // Resolve any import alias (e.g. "from enum import Enum as E" → "Enum")
142 const std::string resolved =
143 json_utils::get_object_alias(ast_json, base["id"].get<std::string>());
144 if (resolved == "Enum")
145 return true;
146 }
147 return false;
148}
149
150// An integer literal, possibly negated (`3`, `-3`).
151inline bool is_literal_int_node(const nlohmann::json &node)
152{
153 if (!node.is_object())
154 return false;
155 if (
156 node.value("_type", "") == "Constant" && node.contains("value") &&
157 node["value"].is_number_integer())
158 return true;
159
160 return node.value("_type", "") == "UnaryOp" && node.contains("op") &&
161 node["op"].value("_type", "") == "USub" && node.contains("operand") &&
162 node["operand"].value("_type", "") == "Constant" &&
163 node["operand"].contains("value") &&
164 node["operand"]["value"].is_number_integer();
165}
166
167inline std::optional<long long> literal_int_value(const nlohmann::json &node)
168{
169 if (!is_literal_int_node(node))
170 return std::nullopt;
171
172 if (node.value("_type", "") == "Constant")
173 return node["value"].get<long long>();
174
175 return -node["operand"]["value"].get<long long>();
176}
177
178// The literal step of a Slice node (1 when omitted); nullopt when it is not
179// a literal or is zero.
180inline std::optional<long long> literal_slice_step(const nlohmann::json &slice)
181{
182 if (!slice.contains("step") || slice["step"].is_null())
183 return 1;
184
185 std::optional<long long> step = literal_int_value(slice["step"]);
186 if (!step || *step == 0)
187 return std::nullopt;
188 return step;
189}
190
191// One literal bound of a Slice node, resolved with Python's rules against an
192// axis of `axis_len` elements; nullopt when the bound is not a literal.
193inline std::optional<long long> literal_slice_bound(
194 const nlohmann::json &slice,
195 const char *name,
196 const long long axis_len,
197 const long long step)
198{
199 const bool lower = std::string(name) == "lower";
200 if (!slice.contains(name) || slice[name].is_null())
201 {
202 if (step > 0)
203 return lower ? 0 : axis_len;
204 return lower ? axis_len - 1 : -1;
205 }
206
207 std::optional<long long> value = literal_int_value(slice[name]);
208 if (!value)
209 return std::nullopt;
210
211 const long long resolved = *value < 0 ? *value + axis_len : *value;
212 if (step > 0)
213 return std::max(0LL, std::min(resolved, axis_len));
214 return std::max(-1LL, std::min(resolved, axis_len - 1));
215}
216
217// Number of elements a Slice with literal bounds and step selects from an
218// axis of `dim` elements; nullopt when any of them is not a literal.
219inline std::optional<std::size_t>
220literal_slice_length(const std::size_t dim, const nlohmann::json &slice)
221{
222 const std::optional<long long> step = literal_slice_step(slice);
223 if (!step)
224 return std::nullopt;
225
226 const long long axis_len = static_cast<long long>(dim);
227 const std::optional<long long> start =
228 literal_slice_bound(slice, "lower", axis_len, *step);
229 const std::optional<long long> stop =
230 literal_slice_bound(slice, "upper", axis_len, *step);
231 if (!start || !stop)
232 return std::nullopt;
233
234 const long long span = *step > 0 ? *stop - *start : *start - *stop;
235 const long long stride = *step > 0 ? *step : -*step;
236 return span <= 0 ? 0 : static_cast<std::size_t>((span - 1) / stride + 1);
237}
238
239} // namespace python_frontend
static const twodig_t base
Definition bigint.cpp:28
typet & type()
Definition irep.h:153
Definition std_types.h:87
void set_access(const irep_idt &access)
Definition std_types.h:136
static void set_member_name(typet &t, const irep_idt &value)
Definition type_utils.h:239
Definition type.h:9
Definition toml.hpp:1531
#define log_warning(fmt,...)
Definition message.h:89
JsonType find_class(const JsonType &ast_json, const std::string &class_name)
Definition json_utils.h:159
const std::string get_object_alias(const JsonType &ast, const std::string &obj_name)
Definition json_utils.h:675
Definition converter_internal.h:17
bool is_literal_int_node(const nlohmann::json &node)
Definition converter_internal.h:151
std::string map_operator(const std::string &op, const typet &type)
Definition converter_internal.h:71
std::optional< std::size_t > literal_slice_length(const std::size_t dim, const nlohmann::json &slice)
Definition converter_internal.h:220
StatementType get_statement_type(const nlohmann::json &element)
Definition converter_internal.h:19
std::optional< long long > literal_slice_step(const nlohmann::json &slice)
Definition converter_internal.h:180
bool is_enum_class(const std::string &class_name, const nlohmann::json &ast_json)
Definition converter_internal.h:130
const std::unordered_map< std::string, std::string > & operator_map()
Definition converter_internal.h:53
std::optional< long long > literal_slice_bound(const nlohmann::json &slice, const char *name, const long long axis_len, const long long step)
Definition converter_internal.h:193
std::optional< long long > literal_int_value(const nlohmann::json &node)
Definition converter_internal.h:167
struct_typet::componentt build_component(const std::string &class_name, const std::string &comp_name, const typet &type)
Definition converter_internal.h:110
const T & max(const T &left, const T &right)
Definition min_max.h:10
const T & min(const T &left, const T &right)
Definition min_max.h:19
static std::string lower(std::string s)
Definition st_fb_translator.cpp:95
StatementType
Definition type_utils.h:18
@ BREAK
Definition type_utils.h:31
@ ASSERT
Definition type_utils.h:27
@ RAISE
Definition type_utils.h:33
@ CONTINUE
Definition type_utils.h:32
@ FOR_STATEMENT
Definition type_utils.h:24
@ EXCEPTHANDLER
Definition type_utils.h:38
@ NONLOCAL
Definition type_utils.h:36
@ WHILE_STATEMENT
Definition type_utils.h:23
@ IF_STATEMENT
Definition type_utils.h:22
@ VARIABLE_ASSIGN
Definition type_utils.h:19
@ TRY
Definition type_utils.h:37
@ UNKNOWN
Definition type_utils.h:34
@ GLOBAL
Definition type_utils.h:35
@ DELETE_STATEMENT
Definition type_utils.h:39
@ PASS
Definition type_utils.h:29
@ COMPOUND_ASSIGN
Definition type_utils.h:20
@ RETURN
Definition type_utils.h:26
@ CLASS_DEFINITION
Definition type_utils.h:28
@ EXPR
Definition type_utils.h:25
@ IMPORT
Definition type_utils.h:30
@ FUNC_DEFINITION
Definition type_utils.h:21