ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
python_converter.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <deque>
5#include <functional>
6#include <nlohmann/json.hpp>
20#include <util/symtab/context.h>
22#include <util/irep/std_code.h>
24#include <functional>
25#include <map>
26#include <optional>
27#include <set>
28#include <tuple>
29#include <unordered_map>
30#include <unordered_set>
31#include <utility>
32#include <vector>
33
34class codet;
35class struct_typet;
36class function_id;
37class symbol_id;
39class type_handler;
40class string_builder;
41class module_locator;
42class tuple_handler;
45class python_lambda;
48
49// Defined in converter_stmt.cpp; shared with numpy_call_expr.cpp so both can
50// verify a Name/Attribute receiver actually resolves to the imported numpy
51// module before treating a call as a numpy constructor/method.
53 const nlohmann::json &ast,
54 const std::string &name);
55
56// One `Call` node together with the name of the function whose body it
57// textually appears in (empty for a module-level call). Declared here (Impl
58// in converter_funcdef.cpp) so python_converter can cache the whole-AST scan
59// that finds these instead of every caller re-walking the AST itself.
61{
62 const nlohmann::json *call;
63 std::string enclosing_function;
64};
65
76{
77public:
79 contextt &_context,
80 const nlohmann::json *ast,
81 const global_scope &gs,
82 const std::vector<nlohmann::json> *extra_asts = nullptr);
83
85
86 void convert();
87
88 // Accessors for handlers
90 {
91 is_converting_rhs = value;
92 }
94 {
95 current_lhs = value;
96 }
97 void set_current_func_name(const std::string &name)
98 {
99 current_func_name_ = name;
100 }
102 {
103 current_element_type = type;
104 }
106 {
107 return symbol_table_.move_symbol_to_context(symbol);
108 }
109
111 const nlohmann::json &target,
112 symbolt *lhs_symbol,
113 const locationt &location);
114
115 const std::string &get_current_func_name() const
116 {
117 return current_func_name_;
118 }
119 const nlohmann::json &get_ast_json() const
120 {
121 return *ast_json;
122 }
123
126 const std::string &var_name,
127 const nlohmann::json &element);
128
129 exprt get_expr(const nlohmann::json &element);
130
141 const std::string &op,
142 exprt &lhs,
143 exprt &rhs,
144 const nlohmann::json &element);
145
146 std::string get_op(const std::string &op, const typet &type) const;
150 const nlohmann::json &annotation,
151 const nlohmann::json &stmt);
154 typet returned_function_type(const nlohmann::json &function_node);
156 const std::string &name,
157 const nlohmann::json &return_node,
158 const nlohmann::json &function_node);
159 typet named_callee_type(const std::string &name);
160 std::optional<code_typet> returned_function(const nlohmann::json &callee);
163 std::optional<exprt> call_returned_function(const nlohmann::json &element);
165 const nlohmann::json &element,
169 const symbolt *
170 lambda_copy_for_call(const nlohmann::json &call, const symbolt &var);
172 bool call_lambda_copy(
173 const nlohmann::json &element,
174 const symbolt &var,
176 const code_typet *&callee_type);
177 std::optional<exprt> call_property_value(const nlohmann::json &element);
180 bool may_be_callable(const typet &type);
182 const typet &function,
183 const typet &value,
184 const locationt &location);
185 void decay_function_choice(exprt &then, exprt &else_expr);
186
188 const nlohmann::json &annotation_node,
189 const nlohmann::json &element);
190
193 typet get_optional_type(const nlohmann::json &slice);
194 typet optional_container_type(const nlohmann::json &slice);
195
197
199 {
200 return dict_handler_;
201 }
202
204 {
205 return *exception_handler_;
206 }
207
209 {
210 return *exception_handler_;
211 }
212
214 {
215 return math_handler_;
216 }
217
219 {
220 return complex_handler_;
221 }
222
224 {
225 return string_handler_;
226 }
227
229 {
230 return *tuple_handler_;
231 }
232
233 const nlohmann::json &ast() const
234 {
235 return *ast_json;
236 }
237
239 {
240 return symbol_table_;
241 }
242
244 {
245 return type_handler_;
246 }
247
249 {
250 return element_type_registry_;
251 }
252
254 {
255 return element_type_registry_;
256 }
257
260 void mark_list_call_escaped(const std::string &id)
261 {
262 call_escaped_lists_.insert(id);
263 }
264
265 bool is_list_call_escaped(const std::string &id) const
266 {
267 return call_escaped_lists_.find(id) != call_escaped_lists_.end();
268 }
269
272 void outlive_scope(const std::string &id);
273
275 void defer_check(std::function<void()> check)
276 {
277 deferred_checks_.push_back(std::move(check));
278 }
279
280 bool type_assertions_enabled() const;
281
282 const std::string &python_file() const
283 {
284 return current_python_file;
285 }
286
287 const std::string &main_python_filename() const
288 {
289 return main_python_file;
290 }
291
292 const std::string &current_function_name() const
293 {
294 return current_func_name_;
295 }
296
297 const std::string &current_classname() const
298 {
299 return current_class_name_;
300 }
301
304 std::string current_ast_scope() const;
305
306 const namespacet &name_space() const
307 {
308 return ns;
309 }
310
312 {
313 return function_call_cache_;
314 }
315
317 {
318 return function_call_cache_;
319 }
320
321 void add_symbol(const symbolt s)
322 {
323 symbol_table_.add(s);
324 }
325
326 void add_instruction(const exprt &expr)
327 {
328 if (current_block)
329 current_block->copy_to_operands(expr);
330 }
331
332 // Converts `ast_node` (an Assign statement) into GOTO and appends it to
333 // current_block, the same way any real source-level assignment is
334 // converted -- for a caller (numpy argument hoisting) that only has
335 // add_instruction's implicit current_block, not a codet& of its own to
336 // pass to get_var_assign directly. False when there is no current block to
337 // emit into (e.g. converting outside statement context).
338 bool emit_statement_into_current_block(const nlohmann::json &ast_node)
339 {
340 if (!current_block || !safe_to_emit_side_effecting_statement())
341 return false;
342 // get_var_assign always leaves current_lhs pointing at its own target
343 // (or null) when it returns, clobbering whatever an enclosing
344 // assignment's own RHS conversion had it pointing at -- e.g. a call
345 // argument hoisted into a temp mid-conversion (hoist_call_argument_
346 // into_temp) would otherwise silently erase the outer assignment's
347 // ability to retype its own target from the freshly computed RHS
348 // (retype_current_lhs_and_return and friends), leaving a stale
349 // static-annotator guess in place. Save and restore around the nested
350 // statement so it only ever affects its own target.
351 exprt *outer_lhs = current_lhs;
352 bool outer_is_converting_rhs = is_converting_rhs;
353 bool outer_is_converting_lhs = is_converting_lhs;
354 const nlohmann::json *outer_store_target = lhs_store_target_;
355 typet outer_element_type = current_element_type;
356 get_var_assign(ast_node, *current_block);
357 current_lhs = outer_lhs;
358 is_converting_rhs = outer_is_converting_rhs;
359 is_converting_lhs = outer_is_converting_lhs;
360 lhs_store_target_ = outer_store_target;
361 current_element_type = outer_element_type;
362 return true;
363 }
364
365 // True where a side-effecting statement (e.g. a hoisted temporary
366 // assignment) is safe to plant into current_block without being evaluated
367 // an extra time or leaking into a specification -- the same guard
368 // needs_zero_division_guard applies before hoisting a side-effecting
369 // divisor: not a lambda body at its definition (operands still unbound),
370 // not the discarded type-probe pass of an assignment RHS (which runs the
371 // real conversion again right after), and not inside a contract clause
372 // (which must not plant a statement into the enclosing block at all).
374 {
375 return !converting_lambda_body_ && !in_rhs_type_probe_ &&
376 !in_contract_clause_;
377 }
378
379 // A runtime guard emitted into current_block runs once, unconditionally,
380 // ahead of the enclosing statement; that is wrong for an expression Python
381 // evaluates conditionally or repeatedly (an and/or tail, a while test).
383 {
384 return current_block && safe_to_emit_side_effecting_statement() &&
385 !in_lazy_operand_;
386 }
387
388 // A raise lowers to a jump to the function's end, which every later state
389 // then merges with, so a guard that only replaces an operational-model
390 // assert is planted only where an enclosing `try` can catch it.
392 {
393 return try_body_depth_ > 0 && can_emit_runtime_guard();
394 }
395
400 const nlohmann::json &lambda_node,
401 const std::string &lambda_id,
402 const locationt &location);
403
404 // Hoists @p operand into a temporary when it carries a side effect, so a
405 // guard and its use evaluate it once.
407 const exprt &operand,
408 const nlohmann::json &element,
409 const std::string &prefix);
410
417 const exprt &base,
418 const std::string &attr_name,
419 const nlohmann::json &element,
420 bool is_self = false);
421
423 const exprt &lhs,
424 const exprt &rhs,
425 const locationt &location);
427 const exprt &cond,
428 const std::string &exception,
429 const std::string &message,
430 const locationt &location);
431
433 const exprt &lhs,
434 const exprt &rhs,
435 const nlohmann::json &element);
436
437 // `tuple + list` or `list + tuple`: raises TypeError unless the list was
438 // built by tuple(x) (#8777), in which case the result is that tuple
439 // concatenated with the other one.
441 const exprt &lhs,
442 const exprt &rhs,
443 const nlohmann::json &element);
444
445 // Raises OverflowError (infinity) or ValueError (NaN) before a float
446 // @p operand is converted to int, and with @p reject_none TypeError for a
447 // pointer @p operand that is None; returns the operand to convert.
449 exprt operand,
450 const nlohmann::json &element,
451 bool reject_none = false);
452
453 // Raises TypeError with @p message before a None-typed @p operand of
454 // float() is converted, when it holds None.
456 exprt operand,
457 const std::string &message,
458 const nlohmann::json &element);
459
461 const exprt &lhs,
462 const exprt &rhs,
463 const nlohmann::json &value);
464
465 void update_symbol(const exprt &expr) const;
466
467 symbolt *find_symbol(const std::string &symbol_id) const;
468
469 bool is_imported_module(const std::string &module_name) const;
474 nlohmann::json callable_function_stubs() const;
476 bool is_retyped(const irep_idt &id) const
477 {
478 return retype_aliases_.count(id.as_string()) > 0;
479 }
480
483 {
484 bool by_import = false;
485 bool by_other = false;
486 bool declared_outer = false;
487 };
488
490 static scope_bindings
491 module_scope_bindings(const nlohmann::json &module, const std::string &name);
498 static std::optional<bool> binding_is_import(
499 const nlohmann::json &module,
500 const scope_bindings &global,
501 const nlohmann::json *function,
502 bool in_class,
503 bool in_order,
504 const std::string &name,
505 const nlohmann::json &use);
510 const nlohmann::json &receiver,
511 const nlohmann::json &use) const;
515 const std::string &module_name,
516 const nlohmann::json &receiver,
517 const nlohmann::json &use) const;
518 std::string current_module_name() const;
519
520 const std::string
521 get_imported_module_path(const std::string &module_name) const
522 {
523 if (imported_modules.find(module_name) != imported_modules.end())
524 return imported_modules.at(module_name);
525
526 return {};
527 }
528
530 const std::string &module,
531 const std::string &name,
532 const std::string &id,
533 const locationt &location,
534 const typet &type) const;
535
536 // Register a ``void name(void)`` C intrinsic in the Python symbol
537 // table if not already present. Used for ESBMC built-ins whose bodies
538 // live in the C library (cprover_library) but whose call sites are
539 // synthesised by the Python frontend (atomic_begin/end, yield, the
540 // pthread main hooks, __pyt_*); the C-style ``c:@F@<name>`` id is
541 // needed so c2goto's linker resolves the call to the library body.
543 const std::string &name,
544 const locationt &location);
545
547 const std::vector<unsigned char> &string_literal,
548 const typet &t);
549
552 exprt make_class_object(const std::string &name);
553
555 exprt class_value(const std::string &name);
558 exprt as_class_value(const exprt &e);
562 const std::string &op,
563 const exprt &lhs,
564 const exprt &rhs);
567 bool binds_runtime_class(const nlohmann::json &ast_node, const exprt &rhs);
572 symbolt *lhs_symbol,
573 exprt &lhs,
574 exprt &rhs,
575 const nlohmann::json &ast_node);
576
579 ExpressionType expression_type(const nlohmann::json &element) const;
580
582 exprt class_mro_tuple(const nlohmann::json &element);
583
584 static bool is_class_object(const exprt &expr)
585 {
586 return expr.is_constant() && expr.type().is_array() &&
587 !expr.get("value").empty();
588 }
589
590 exprt get_literal(const nlohmann::json &element);
591
592 locationt get_location_from_decl(const nlohmann::json &element) const;
593
595 const nlohmann::json &from,
596 nlohmann::json &to) const;
597
599 const std::string &op,
600 exprt &lhs,
601 exprt &rhs,
602 const nlohmann::json &element);
603
604 bool scalar_order(
605 exprt a,
606 exprt b,
607 const nlohmann::json &element,
608 expr2tc &lt,
609 expr2tc &eq);
610
612 exprt &lhs,
613 exprt &rhs,
614 const nlohmann::json &element);
615
617 const std::string &op,
618 const exprt &lhs,
619 const exprt &rhs,
620 size_t unordered,
621 const expr2tc &prefix_eq,
622 const nlohmann::json &element);
623
626
629 bool enter_contract_clause(bool entering)
630 {
631 return std::exchange(in_contract_clause_, in_contract_clause_ || entering);
632 }
633 void restore_contract_clause(bool saved)
634 {
635 in_contract_clause_ = saved;
636 }
638 {
639 return in_contract_clause_;
640 }
642 {
643 return current_block ? current_block->operands().size() : 0;
644 }
645
649 const std::string *class_object_name(const irep_idt &id) const
650 {
651 auto it = class_object_names_.find(id);
652 return it == class_object_names_.end() ? nullptr : &it->second;
653 }
654
655private:
656 // Hoists @p operand once and plants @p emit_guards over its value where the
657 // operand is evaluated, also inside an and/or tail or a while test.
658 exprt guard_operand(
659 exprt operand,
660 const nlohmann::json &element,
661 const std::string &prefix,
662 const std::function<void(const expr2tc &, const locationt &)> &emit_guards);
663
664 friend class bounded_math;
665 friend class complex_handler;
666 friend class function_call_expr;
667 friend class numpy_call_expr;
668 friend class numpy_random;
669 friend class numpy_nditer;
671 friend class type_handler;
672 friend class python_list;
673 friend class string_handler;
674 friend class tuple_handler;
679 friend class python_set;
683
684 template <typename Func>
685 decltype(auto) with_ast(const nlohmann::json *new_ast, Func &&f)
686 {
687 const nlohmann::json *old_ast = ast_json;
688 ast_json = new_ast;
689 auto result = f();
690 ast_json = old_ast;
691 return result;
692 }
693
694 void load_c_intrisics(code_blockt &block);
695
696 void get_var_assign(const nlohmann::json &ast_node, codet &target_block);
697
698 void preregister_global_variables(const nlohmann::json &ast_body);
699
705 std::string annotated_optional_class(const nlohmann::json &annotation) const;
706
707 typet
708 resolve_variable_type(const std::string &var_name, const locationt &loc);
709
710 void get_compound_assign(const nlohmann::json &ast_node, codet &target_block);
711
715 symbolt *find_symbol_in_enclosing_scopes(const std::string &name);
716
717 symbolt *resolve_subscript_base_symbol(
718 const nlohmann::json &target,
719 const std::string &name,
720 symbolt *found);
721
724 void mark_augassign_list_escaped(const exprt &lhs, const exprt &rhs);
725
726 void
727 get_return_statements(const nlohmann::json &ast_node, codet &target_block);
728 void get_return_with_conditional_spelling(
729 const nlohmann::json &ast_node,
730 codet &target_block);
731
732 void get_function_definition(const nlohmann::json &function_node);
733
739 exprt dispatch_mismatched_callees(
740 const exprt &callee,
741 const nlohmann::json &call,
742 const side_effect_expr_function_callt &call_expr);
743
744 exprt get_function_body_or_unsupported(const nlohmann::json &function_node);
745
748 static exprt hoist_local_declarations(exprt body);
749
750 bool function_may_be_called(const nlohmann::json &function_node) const;
751
752 void
753 get_class_definition(const nlohmann::json &class_node, codet &target_block);
754
755 exprt get_unary_operator_expr(const nlohmann::json &element);
756
759 exprt get_named_expr(const nlohmann::json &element);
760
765 static bool contains_named_expr(const nlohmann::json &node);
766
768 static bool contains_nested_scope_named_expr(const nlohmann::json &node);
769
770 exprt get_binary_operator_expr(const nlohmann::json &element);
772 std::optional<exprt> try_bound_method_compare(const nlohmann::json &element);
775 std::optional<std::pair<exprt, std::string>>
776 bound_method_operand(const nlohmann::json &operand);
777 exprt get_binary_operator_expr(
778 const nlohmann::json &element,
779 const nlohmann::json &left,
780 const nlohmann::json &right,
781 const std::string &op,
782 exprt &lhs,
783 exprt &rhs);
784 exprt
785 keep_operand_calls(const exprt &result, const exprt &lhs, const exprt &rhs);
786
791 exprt checked_erased_int(
792 exprt operand,
793 const nlohmann::json &node,
794 const nlohmann::json &element);
796 exprt get_right_operand_expr(
797 const nlohmann::json &element,
798 const nlohmann::json &right,
799 const exprt &lhs);
800 exprt build_division_guarded_binop(
801 const std::string &op,
802 exprt lhs,
803 exprt rhs,
804 const nlohmann::json &element);
805 exprt build_arithmetic_binop(
806 const std::string &op,
807 exprt lhs,
808 exprt rhs,
809 const nlohmann::json &element);
811 std::vector<typet>
812 percent_arg_types(const nlohmann::json &right, const exprt &rhs) const;
815 exprt get_fstring_in_order(const nlohmann::json &joined);
818 exprt get_percent_format_expr(
819 const nlohmann::json &left,
820 const std::vector<nlohmann::json> &args,
821 const std::map<std::string, nlohmann::json> &mapping,
822 const std::vector<typet> &arg_types);
823
834 std::string get_python_type_category(const typet &t) const;
835
836 bool is_bytes_literal(const nlohmann::json &element);
837
838 // V.3: build the `is` identity equality in IREP2 (shared by the `is` and
839 // `is not` paths); the public wrappers back-migrate once at the legacy seam.
840 expr2tc build_is_equality(
841 const exprt &lhs,
842 const exprt &rhs,
843 const nlohmann::json &left,
844 const nlohmann::json &right);
845
846 exprt get_binary_operator_expr_for_is(
847 const exprt &lhs,
848 const exprt &rhs,
849 const nlohmann::json &left,
850 const nlohmann::json &right);
851
852 exprt get_negated_is_expr(
853 const exprt &lhs,
854 const exprt &rhs,
855 const nlohmann::json &left,
856 const nlohmann::json &right);
857
858 exprt get_resolved_value(const exprt &expr);
859
860 exprt get_function_constant_return(const exprt &func_value);
861
862 exprt resolve_function_call(const exprt &func_expr, const exprt &args_expr);
863
864 exprt get_lambda_expr(
865 const nlohmann::json &element,
866 const std::vector<std::optional<typet>> &argument_types = {});
867
868 codet convert_expression_to_code(exprt &expr);
869
870 std::string remove_quotes_from_type_string(const std::string &type_string);
871
872 bool function_has_missing_return_paths(const nlohmann::json &function_node);
873
874 bool function_is_generator(const nlohmann::json &function_node);
875
876 exprt materialize_list_function_call(
877 const exprt &expr,
878 const nlohmann::json &element,
879 codet &target_block);
880
881 std::optional<typet> call_dict_value_type(const nlohmann::json &call);
882
883 symbolt create_return_temp_variable(
884 const typet &return_type,
885 const locationt &location,
886 const std::string &func_name);
887
888 // Stage 1 object-model migration (#3067): copy a constructed class *value*
889 // onto a fresh non-expiring `__ESBMC_new_object` heap object and return the
890 // pointer to it, so a `-> Cls` function can hand back a `Cls*` reference that
891 // survives its frame. `current_func_return_type_` must be the migrated
892 // pointer type. Used by both return paths in get_return_statements.
893 exprt box_value_on_heap(
894 const exprt &value,
895 const locationt &location,
896 codet &target_block);
897
898 // Same, but boxing behind an explicit pointer type instead of
899 // `current_func_return_type_` (e.g. `char (*)[N]` for a local string
900 // array whose bytes must survive the frame, #5571).
901 exprt box_value_on_heap(
902 const exprt &value,
903 const locationt &location,
904 codet &target_block,
905 const typet &ptr_type);
906
907 void register_instance_attribute(
908 const std::string &symbol_id,
909 const std::string &attr_name,
910 const std::string &var_name,
911 const std::string &class_tag);
912
916 void reject_maybe_unset_instance_attr(
917 bool instance_written,
918 const symbolt &symbol,
919 const std::string &var_name,
920 const std::string &attr_name,
921 const std::string &obj_type_name);
922
923 bool is_instance_attribute(
924 const std::string &symbol_id,
925 const std::string &attr_name,
926 const std::string &var_name,
927 const std::string &class_tag);
928
929 exprt create_member_expression(
930 const symbolt &symbol,
931 const std::string &attr_name,
932 const typet &attr_type);
933
934 typet clean_attribute_type(const typet &attr_type);
935
936 std::string create_normalized_self_key(const std::string &class_tag);
937
938 std::string extract_class_name_from_tag(const std::string &tag_name);
939
942 symbolt *find_class_attribute_symbol(
943 const std::string &class_name,
944 const std::string &attr_name);
945
949 std::vector<dynamic_type_detail::numeric_bindingt> scope_numeric_bindings(
950 const std::string &name,
951 int before,
952 bool include_later) const;
953
954 void reject_inexact_number_join(
955 const nlohmann::json &element,
956 const exprt &expr) const;
957
958 // The class name `t` names, or empty when it is neither a struct nor a
959 // `tag-<Class>` symbol reference.
960 std::string class_name_of(const typet &t);
961
962 // True iff `t` denotes a user-defined Python class struct — either the struct
963 // itself or a `symbol_typet("tag-<Class>")` reference to it (robust to
964 // whether the struct has been built yet). Excludes the list/dict/object model
965 // structs.
966 bool is_user_class_struct_type(const typet &t);
967
968 // True iff `t` is a user class the object model migrates to the heap and
969 // stores in a container as a `Class*`. A reserved `__ESBMC` name opts out:
970 // the push and read paths must agree on which classes stay inline, so both
971 // gate on this one predicate (#7685).
972 bool is_heap_migrated_class_type(const typet &t);
973
974 // True iff `t` is a pointer to a user-defined class struct (a migrated
975 // `Class*` instance). Used to gate the object-model migration's
976 // None-keeps-Class* and dunder-dispatch-through-pointer paths to real
977 // classes.
978 bool is_user_class_pointer(const typet &t);
979
980 // Widen a symbol rebound from a non-class placeholder (None, Any, a bare
981 // scalar) to a class-pointer binding. Only those types are widened: a
982 // struct-shaped one may already back an expression built elsewhere.
983 void retype_placeholder_to_class(symbolt &sym, const typet &new_type);
984
985 exprt resolve_identity_function_call(
986 const exprt &func_expr,
987 const exprt &args_expr);
988
989 bool is_identity_function(
990 const exprt &func_value,
991 const std::string &func_identifier);
992
993 exprt handle_none_comparison(
994 const std::string &op,
995 const exprt &lhs,
996 const exprt &rhs);
997
1000 exprt handle_none_operand(
1001 const std::string &op,
1002 const exprt &lhs,
1003 const exprt &rhs);
1004
1005 void raise_on_optional_none(
1006 const std::string &op,
1007 const exprt &lhs_none,
1008 const exprt &rhs_none,
1009 const exprt &lhs,
1010 const exprt &rhs,
1011 const nlohmann::json &element);
1012
1018 exprt try_lower_slice_member_is_none(
1019 const std::string &op,
1020 const exprt &lhs,
1021 const exprt &rhs);
1022
1023 symbolt &create_tmp_symbol(
1024 const nlohmann::json &element,
1025 const std::string var_name,
1026 const typet &symbol_type,
1027 const exprt &symbol_value);
1028
1032 symbolt &create_tmp_symbol(
1033 const locationt &location,
1034 const std::string var_name,
1035 const typet &symbol_type,
1036 const exprt &symbol_value);
1037
1038 exprt get_logical_operator_expr(const nlohmann::json &element);
1039
1040 exprt get_boolop_operand(
1041 const nlohmann::json &operand,
1042 std::vector<code_blockt> &effects);
1043
1044 exprt lower_short_circuit_boolop(
1045 const exprt &logical_expr,
1046 const std::vector<code_blockt> &effects,
1047 const std::function<exprt(const exprt &)> &truthy,
1048 const nlohmann::json &element);
1049
1050 exprt emit_guarded_boolop(
1051 const exprt &logical_expr,
1052 const std::vector<code_blockt> &effects,
1053 const std::function<exprt(const exprt &)> &truthy,
1054 const locationt &location);
1055
1060 exprt get_flat_boolop_test(
1061 const nlohmann::json &test_node,
1062 const std::function<exprt(const exprt &, const nlohmann::json &)> &to_bool);
1063
1064 exprt get_conditional_stm(const nlohmann::json &ast_node);
1065
1077 bool rewrite_divergent_conditional_assign(
1078 const nlohmann::json &ast_node,
1079 codet &target_block);
1080
1081 std::string instantiated_class(const nlohmann::json &value) const;
1082
1083 bool ternary_needs_if_spelling(const nlohmann::json &ifexp) const;
1084 void reject_divergent_attribute_classes(
1085 const nlohmann::json &target,
1086 const nlohmann::json &ifexp) const;
1087
1088 bool is_coverage_mode() const;
1089
1090 bool is_assert_fold_disabled() const;
1091
1092 bool is_pytest_generation_mode() const;
1093
1094 bool is_model_file(const nlohmann::json &node) const;
1095
1101 bool is_program_file(const std::string &file) const;
1102
1103 exprt get_function_call(const nlohmann::json &ast_block);
1106 exprt get_call_expr(const nlohmann::json &element);
1107
1111 exprt get_len_on_class_instance(const nlohmann::json &element);
1112 static bool is_pure_read(const nlohmann::json &node);
1113 exprt
1114 get_len_on_list_element(const nlohmann::json &arg, const locationt &location);
1115 static exprt list_element_type_id(const exprt &value);
1116 std::size_t count_user_classes();
1117 exprt checked_len_result(const exprt &len_call, const locationt &location);
1118
1119 // len(v) where v is a pointer-backed numpy view (ADR-NP-003 etapa 2, 1-D
1120 // slice views). Split out of get_function_call() to keep that already
1121 // large function's own decision count from growing further; see
1122 // converter_funcall.cpp for the full rationale.
1123 std::optional<exprt>
1124 try_get_numpy_pointer_view_len(const nlohmann::json &element);
1125 std::optional<exprt>
1126 try_get_numpy_named_pointer_view_len(const nlohmann::json &arg) const;
1127 std::optional<exprt> try_get_numpy_subscript_pointer_view_len(
1128 const nlohmann::json &arg,
1129 const nlohmann::json &element);
1130
1131 // v.shape / v.ndim where v is a pointer-backed numpy view (ADR-NP-003
1132 // etapa 2, 1-D slice views): unwrapping the pointer only reaches the
1133 // scalar element type, not a shape, so the view's own tracked logical
1134 // length is used instead. Split out of get_expr() to keep that already
1135 // large function's own decision count from growing further; see
1136 // converter_expr.cpp for the full rationale. Returns std::nullopt for
1137 // any other attribute or an untracked symbol, so the caller falls
1138 // through to the existing array/list handling.
1139 std::optional<exprt> try_get_numpy_pointer_view_shape_attr(
1140 const symbolt &symbol,
1141 const std::string &attr_name);
1142
1143 // v.shape / v.ndim / v.size where v is a 2-D+ numpy array parameter: its
1144 // full logical shape is tracked in numpy_param_shapes_ (populated by
1145 // register_function_argument before the C-ABI row-pointer decay erases the
1146 // outer dimension). Mirrors try_get_numpy_pointer_view_shape_attr's split
1147 // reasoning. Returns std::nullopt for any other attribute or an untracked
1148 // symbol, so the caller falls through to the existing array/list handling.
1149 std::optional<exprt> try_get_numpy_param_shape_attr(
1150 const symbolt &symbol,
1151 const std::string &attr_name);
1152
1153 // Tries try_get_numpy_pointer_view_shape_attr then
1154 // try_get_numpy_param_shape_attr, so get_expr's own Attribute dispatch
1155 // needs a single `if` for both tracked-shape sources instead of growing
1156 // its own decision count by one per source.
1157 std::optional<exprt>
1158 try_get_numpy_shape_attr(const symbolt &symbol, const std::string &attr_name);
1159
1160 std::optional<std::vector<std::size_t>>
1161 tracked_numpy_shape_from_name(const std::string &name) const;
1162
1163 std::optional<std::vector<std::size_t>>
1164 numpy_shape_from_indexed_decl(const std::string &name) const;
1165
1166 exprt numpy_shape_attr_expr(
1167 const std::vector<std::size_t> &shape,
1168 const std::string &attr_name);
1169
1170 std::optional<std::vector<std::size_t>>
1171 get_numpy_constructor_shape(const nlohmann::json &node) const;
1172
1173 std::optional<exprt> try_get_numpy_value_shape_attr(
1174 const exprt &base_expr,
1175 const nlohmann::json &base_node,
1176 const std::string &attr_name);
1177
1178 std::optional<exprt>
1179 try_get_numpy_shape_subscript(const nlohmann::json &element) const;
1180
1181 std::optional<exprt> try_get_numpy_tracked_value_shape_attr(
1182 const exprt &base_expr,
1183 const nlohmann::json &base_node,
1184 const std::string &attr_name);
1185
1186 void reject_numpy_shape_attr_on_nonobject_call_result(
1187 const exprt &base_expr,
1188 const nlohmann::json &base_node,
1189 const std::string &attr_name);
1190
1191 bool should_reject_numpy_shape_attr_on_symbol(
1192 const symbolt &symbol,
1193 const std::string &attr_name);
1194
1195 std::optional<exprt> try_get_numpy_bool_mask_rows_shape_attr(
1196 const exprt &base_expr,
1197 const typet &base_type,
1198 const std::string &attr_name);
1199
1200 exprt get_block(
1201 const nlohmann::json &ast_block,
1202 bool is_function_body = false,
1203 bool is_loop_body = false);
1204
1205 exprt get_static_array(const nlohmann::json &arr, const typet &shape);
1206
1207 void adjust_statement_types(exprt &lhs, exprt &rhs) const;
1208
1209 symbol_id create_symbol_id() const;
1210
1223 void find_entry_function(
1224 const std::string &target,
1225 nlohmann::json &node,
1226 std::string &owning_class) const;
1227
1228 symbol_id create_symbol_id(const std::string &filename) const;
1229
1230 void promote_int_to_float(exprt &op, const typet &target_type) const;
1231
1232 void handle_float_division(exprt &lhs, exprt &rhs, exprt &bin_expr) const;
1233
1234 exprt get_tuple_expr(const nlohmann::json &element);
1235
1243 exprt build_slice_object(const nlohmann::json &slice_node);
1244
1252 exprt build_slice_from_args(
1253 const nlohmann::json &args,
1254 const nlohmann::json &source_node);
1255
1256 std::pair<exprt, exprt>
1257 resolve_comparison_operands_internal(const exprt &lhs, const exprt &rhs);
1258
1259 bool
1260 has_unsupported_side_effects_internal(const exprt &lhs, const exprt &rhs);
1261
1262 TypeFlags infer_types_from_returns(const nlohmann::json &function_body);
1263
1264 void process_function_arguments(
1265 const nlohmann::json &function_node,
1266 code_typet &type,
1267 const symbol_id &id,
1268 const locationt &location);
1269
1270 // Records a numpy array parameter's pre-decay shape (when 2-D+) and its
1271 // tracked-array-symbol status once its arg_id is known. Split out of
1272 // register_function_argument to keep that function's own decision count
1273 // down -- both conditions live in here instead of as two more `if`s there.
1274 void track_numpy_param(
1275 const std::string &arg_id,
1276 const std::optional<std::vector<std::size_t>> &numpy_param_full_shape,
1277 bool numpy_array_param,
1278 const typet &array_type);
1279
1280 // A numpy array parameter decays to a pointer; element-wise arithmetic
1281 // reads it back through its pre-decay array type.
1282 exprt numpy_param_as_array(const exprt &operand) const;
1283 exprt snapshot_left_operand(
1284 const nlohmann::json &left,
1285 const exprt &lhs,
1286 const nlohmann::json &right);
1287 bool may_rebind_left(
1288 const nlohmann::json &left,
1289 const exprt &lhs,
1290 const nlohmann::json &right) const;
1291 bool calls_user_code(const nlohmann::json &node) const;
1292 exprt
1293 materialize_numpy_arithmetic(const nlohmann::json &node, const exprt &value);
1294 std::optional<std::vector<std::size_t>>
1295 numpy_param_shape(const std::string &symbol_id) const;
1296
1297 size_t register_function_argument(
1298 const nlohmann::json &element,
1299 code_typet &type,
1300 const symbol_id &id,
1301 const locationt &location,
1302 bool is_keyword_only);
1303
1315 code_blockt create_capture_cells(
1316 const nlohmann::json &function_node,
1317 const symbol_id &id,
1318 const locationt &location);
1319
1320 code_blockt bind_capture_cells(
1321 const std::set<std::string> &free_names,
1322 const std::string &enclosing_scope,
1323 const std::string &func_id,
1324 const locationt &location);
1325
1328 code_blockt pending_captures_;
1329
1332 const nlohmann::json *enclosing_function_node_ = nullptr;
1333
1352 bool try_infer_numpy_param_type(
1353 const std::string &func_name,
1354 size_t param_index,
1355 typet &out,
1356 std::set<std::string> &visiting) const;
1357
1358 // A call-site argument that resolves to a numpy array's element type: a
1359 // literal `np.array([...])` call (is_numpy_array_literal_call), or a
1360 // `Call` to a user function whose body unconditionally returns one
1361 // (numpy_array_literal_return in converter_funcdef.cpp). nullopt for
1362 // anything else. Replaces try_infer_numpy_param_type's own former
1363 // is_numpy_array_literal_call() check one-for-one (same call count there)
1364 // instead of adding a second, separate dispatch branch for the `Call`
1365 // case, to keep that function's own decision count down.
1366 std::optional<typet> try_infer_numpy_array_arg_type(
1367 const nlohmann::json &arg,
1368 const nlohmann::json &module_body) const;
1369
1376 bool try_infer_dynamic_param_type(
1377 const std::string &callee,
1378 const std::string &param_name,
1379 size_t param_index) const;
1380
1381 typet ctor_param_attr_type(
1382 const std::vector<const nlohmann::json *> &module_bodies,
1383 const std::string &class_name,
1384 const std::string &param_name,
1385 int param_idx) const;
1386
1387 void reject_one_sided_tagged_store(const exprt &lhs, const exprt &rhs) const;
1388
1397 bool infer_bytes_param_size_from_call_sites(
1398 const std::string &func_name,
1399 size_t param_index,
1400 long long &out_size) const;
1401 bool infer_bytes_param_size_from_call_sites(
1402 const std::string &func_name,
1403 size_t param_index,
1404 long long &out_size,
1405 std::set<std::string> &visiting) const;
1406
1410 std::optional<long long> resolve_forwarded_bytes_param_size(
1411 const nlohmann::json &arg,
1412 const nlohmann::json &module_body,
1413 const std::string &enclosing_function,
1414 std::set<std::string> &visiting) const;
1415
1420 std::optional<long long> resolve_bytes_call_site_arg_size(
1421 const std::string &enclosing_function,
1422 const nlohmann::json &call,
1423 size_t param_index,
1424 const nlohmann::json &module_body,
1425 std::set<std::string> &visiting) const;
1426
1431 std::optional<typet> try_infer_bytes_param_size(
1432 const std::string &arg_name,
1433 const typet &arg_type,
1434 const symbol_id &id,
1435 size_t param_index) const;
1436
1437 void validate_return_paths(
1438 const nlohmann::json &function_node,
1439 const code_typet &type,
1440 exprt &function_body);
1441
1442 exprt compare_constants_internal(
1443 const std::string &op,
1444 const exprt &lhs,
1445 const exprt &rhs);
1446
1447 exprt handle_indexed_comparison_internal(
1448 const std::string &op,
1449 const exprt &lhs,
1450 const exprt &rhs);
1451
1452 exprt handle_type_mismatches(
1453 const std::string &op,
1454 const exprt &lhs,
1455 const exprt &rhs);
1456
1457 typet
1458 any_attribute_type(const nlohmann::json &stmt, const std::string &attr_name);
1459 void get_attributes_from_self(
1460 const nlohmann::json &func_node,
1461 struct_typet &clazz);
1462
1463 // Infer the static type of `class_name.attr_name` by scanning non-None
1464 // assignments to that attribute — both `self.attr = <rhs>` within the
1465 // class's own methods and `<var>.attr = <rhs>` at module scope where
1466 // `<var>` was assigned `class_name(...)`. Returns nil if no useful
1467 // information is found (caller falls back to any_type()).
1468 typet infer_attr_type_from_usage(
1469 const std::string &class_name,
1470 const std::string &attr_name);
1471
1472 // The entry module, every imported module and the current one, each once.
1473 std::vector<const nlohmann::json *> reachable_module_bodies() const;
1474
1475 // None when every write to an attribute named `attr_name` stores None, and
1476 // Optional[T] when they store None and literals of one scalar type T.
1477 // any_type() for any other write or a setattr call.
1478 typet none_attribute_type(const std::string &attr_name) const;
1479
1480 bool held_by_reference(
1481 bool rhs_is_aliased_name,
1482 const std::string &attr_name,
1483 const typet &type,
1484 const std::string &annotated_type) const;
1485
1486 // Attributes stored None that none_attribute_type could not type: those
1487 // whose every write is a plain store carry a None flag per instance, the
1488 // others are refused in arithmetic.
1489 mutable std::set<std::string> untyped_none_attributes_;
1490 mutable std::set<std::string> none_flagged_attributes_;
1491
1492 void add_none_flag_component(
1493 struct_typet &clazz,
1494 const std::string &attr_name) const;
1495 exprt none_flag_of_attribute(const exprt &operand) const;
1496 void guard_none_attribute_operands(
1497 const std::string &op,
1498 const nlohmann::json &left,
1499 const nlohmann::json &right,
1500 const exprt &lhs,
1501 const exprt &rhs,
1502 const nlohmann::json &element);
1503 void set_none_flag(
1504 const exprt &lhs,
1505 const nlohmann::json &ast_node,
1506 codet &target_block) const;
1507
1524 typet infer_tuple_struct_from_value(
1525 const nlohmann::json &value_node,
1526 const std::unordered_map<std::string, nlohmann::json> &param_annotations);
1527
1528 exprt get_return_from_func(const char *func_symbol_id);
1529
1530 void create_builtin_symbols();
1531
1532 bool import_module_into_block(
1533 const nlohmann::json &import_node,
1534 module_locator &locator,
1535 code_blockt &code);
1536
1537 bool import_one_module(
1538 const nlohmann::json &import_node,
1539 module_locator &locator,
1540 code_blockt &code);
1541
1542 std::vector<const nlohmann::json *>
1543 import_nodes(std::deque<nlohmann::json> &submodules) const;
1544
1545 std::string module_source_file(
1546 const std::string &module,
1547 const module_locator &locator) const;
1548
1552 std::vector<nlohmann::json> submodule_imports(
1553 const nlohmann::json &import_node,
1554 const module_locator &locator) const;
1555
1558 void register_import_alias(
1559 const nlohmann::json &import_node,
1560 const std::string &module_file);
1561
1569 void convert_module_imports(code_blockt &all_imports_block);
1570
1578 void convert_extra_translation_unit(
1579 const nlohmann::json &extra_ast,
1580 code_blockt &init_code,
1581 code_blockt &combined_user_code);
1582
1583 nlohmann::json build_dunder_call(
1584 const nlohmann::json &object,
1585 const std::string &dunder_name,
1586 const nlohmann::json &args,
1587 const nlohmann::json &source_node) const;
1588
1591 exprt store_call_result(
1592 exprt call_expr,
1593 const locationt &location,
1594 const std::string &temp_prefix,
1595 codet *block = nullptr);
1596
1597 void process_module_imports(
1598 const nlohmann::json &module_ast,
1599 module_locator &locator,
1600 code_blockt &accumulated_code);
1601
1609 void pre_collect_module_asts(
1610 const nlohmann::json &module_ast,
1611 module_locator &locator);
1612 void pre_collect_import(const nlohmann::json &node, module_locator &locator);
1613
1614 symbolt *find_function_in_base_classes(
1615 const std::string &class_name,
1616 const std::string &symbol_id,
1617 std::string method_name,
1618 bool is_ctor) const;
1619
1623 symbolt *find_function_in_imported_base_classes(
1624 const std::string &class_name,
1625 const std::string &method_name,
1626 bool is_ctor) const;
1627
1631 std::pair<const nlohmann::json *, std::string>
1632 find_imported_class_module(const std::string &class_name) const;
1633
1636 symbolt *find_method_in_imported_base(
1637 const nlohmann::json &base_class_node,
1638 const std::string &base_class,
1639 const std::string &method_name,
1640 bool is_ctor) const;
1641
1644 symbolt *find_method_in_model_base(
1645 const std::string &base_class,
1646 const std::string &sym_id) const;
1647
1650 const scope_bindings &module_bindings(const std::string &name) const;
1651 mutable std::
1652 map<std::pair<const nlohmann::json *, std::string>, scope_bindings>
1653 module_bindings_memo_;
1654 using mro_memo =
1655 std::map<std::string, std::optional<std::vector<std::string>>>;
1656
1661 std::optional<std::vector<std::string>>
1662 class_mro(const std::string &class_name) const;
1663 std::optional<std::vector<std::string>>
1664 class_mro(const std::string &class_name, mro_memo &memo) const;
1665 static std::optional<std::vector<std::string>>
1666 c3_merge(std::vector<std::vector<std::string>> seqs);
1669 const nlohmann::json *sole_binding(
1670 const std::string &name,
1671 const std::string &statement = "ClassDef") const;
1674 const nlohmann::json *sole_method_def(
1675 const std::string &class_name,
1676 const std::string &method) const;
1680 bool overridden_below(
1681 const std::string &class_name,
1682 const std::string &method) const;
1683
1687 struct attribute_functions
1688 {
1689 bool bound;
1690 std::vector<std::string> ids;
1691 };
1694 const attribute_functions *function_attribute(const std::string &attr);
1695 static bool same_signature(const code_typet &a, const code_typet &b);
1696 void collect_attribute_stores(
1697 const nlohmann::json &node,
1698 const std::string &owner,
1699 const nlohmann::json *method);
1700 void record_function_store(
1701 const std::string &attr,
1702 const std::pair<bool, std::string> &stored);
1704 std::set<std::string> subclasses(const std::string &class_name) const;
1705 std::optional<std::pair<bool, std::string>> stored_function(
1706 const nlohmann::json &target,
1707 const nlohmann::json &value,
1708 const std::string &owner,
1709 const nlohmann::json *method) const;
1712 std::optional<std::string>
1713 bound_method_id(const std::string &owner, const std::string &m) const;
1714 bool try_bound_method_store(const nlohmann::json &ast_node, codet &block);
1717 bool try_dedicated_assign(const nlohmann::json &ast_node, codet &block);
1718 bool try_numpy_nditer_assign(const nlohmann::json &ast_node);
1719 const nlohmann::json *
1720 numpy_slice_copy_source(const nlohmann::json &value) const;
1721 bool try_numpy_slice_copy_assign(const nlohmann::json &ast_node);
1722 std::optional<exprt> get_intercepted_expr(const nlohmann::json &element);
1723 void reject_bound_method_read(const nlohmann::json &element);
1724 exprt get_class_dunder_attribute(const nlohmann::json &element);
1725 exprt get_class_attribute(const nlohmann::json &element);
1726 exprt get_class_name(const nlohmann::json &value);
1727 exprt
1728 get_module_member(const std::string &var_name, const nlohmann::json &element);
1729 void reject_method_value(const std::string &class_name, const std::string &m)
1730 const;
1733 std::map<
1734 const nlohmann::json *,
1735 std::optional<std::map<std::string, std::optional<attribute_functions>>>>
1736 attribute_functions_;
1739 bool class_binds_name(const std::string &class_name, const std::string &name)
1740 const;
1741
1742 symbolt *find_imported_symbol(const std::string &symbol_id) const;
1745 symbolt *find_symbol_through_module(const std::string &sym_id) const;
1746 symbolt *find_nested_function_symbol(const std::string &name) const;
1747 symbolt *find_symbol_in_global_scope(const std::string &symbol_id) const;
1748 symbolt *find_model_symbol(const std::string &sym_id) const;
1749 void collect_model_namespaces();
1750 void build_models_block(code_blockt &models_block, bool models_precompiled);
1751
1752 void copy_instance_attributes(
1753 const std::string &src_obj_id,
1754 const std::string &target_obj_id);
1755
1756 void update_instance_from_self(
1757 const std::string &class_name,
1758 const std::string &func_name,
1759 const std::string &obj_symbol_id);
1760
1761 void refuse_misaligned_self_calls() const;
1762 void refuse_misaligned_self_call(
1763 const code_function_callt &call,
1764 const namespacet &ns) const;
1765
1766 size_t get_type_size(const nlohmann::json &ast_node);
1767
1768 void append_models_from_directory(
1769 std::list<std::string> &file_list,
1770 const std::string &dir_path);
1771
1772 typet nullable_dict_pointee(const typet &t) const;
1773 bool keeps_pointer_type_on_none(const typet &t);
1774 void guard_none_container(
1775 exprt &rhs,
1776 typet &rhs_type,
1777 const nlohmann::json &element);
1778 void guard_none_typed_container(
1779 const std::string &op,
1780 exprt &rhs,
1781 const nlohmann::json &element);
1782 exprt handle_membership_operator(
1783 exprt &lhs,
1784 exprt &rhs,
1785 const nlohmann::json &element,
1786 bool invert);
1787 exprt range_membership(const exprt &x, const nlohmann::json &element);
1788 exprt
1789 list_or_range_contains(exprt &lhs, exprt &rhs, const nlohmann::json &element);
1790
1793 typet get_union_type_from_annotation(
1794 const nlohmann::json &annotation_node,
1795 const nlohmann::json &element);
1796
1797 typet narrow_union_to_member(const std::string &member_name);
1798
1799 std::string extract_non_none_type(const nlohmann::json &annotation_node);
1800
1801 void
1802 get_delete_statement(const nlohmann::json &ast_node, codet &target_block);
1803
1804 // =========================================================================
1805 // Helper methods for get_var_assign
1806 // =========================================================================
1807
1808 std::pair<std::string, typet>
1809 extract_type_info(const nlohmann::json &ast_node);
1810
1813 void upgrade_param_type_from_default(
1814 code_typet::argumentt &param_arg,
1815 const exprt &default_expr);
1816
1818 void refine_any_param_to_list(
1819 code_typet::argumentt &param_arg,
1820 const nlohmann::json &body,
1821 const std::string &func_name,
1822 size_t param_index);
1823
1825 bool param_is_list_like(
1826 const std::string &param_name,
1827 const nlohmann::json &body,
1828 const std::string &func_name,
1829 size_t param_index,
1830 typet &elem_type) const;
1831
1832 bool called_only_with_flat_list_displays(
1833 const std::string &func_name,
1834 size_t param_index) const;
1835
1837 void refine_any_param_from_elements(
1838 code_typet::argumentt &param_arg,
1839 const std::string &func_name,
1840 size_t param_index);
1841
1843 void seed_list_param_element_type(
1844 const nlohmann::json &element,
1845 const symbol_id &id,
1846 const std::string &arg_id,
1847 size_t param_index);
1848
1850 bool seed_mixed_call_site_elements(
1851 const std::string &param_id,
1852 const std::string &func_name,
1853 size_t param_index);
1854 bool infer_list_elem_type_from_call_sites(
1855 const std::string &func_name,
1856 size_t param_index,
1857 typet &out) const;
1858 bool param_keeps_positions(
1859 const std::string &func_name,
1860 size_t param_index,
1861 bool any_index = false) const;
1862 bool param_elements(
1863 const nlohmann::json &arg,
1864 const std::string &enclosing_function,
1865 std::vector<nlohmann::json> &out,
1866 bool &direct,
1867 unsigned depth) const;
1868 bool call_site_list_literals(
1869 const std::string &func_name,
1870 size_t param_index,
1871 std::vector<nlohmann::json> &out,
1872 bool &direct,
1873 unsigned depth) const;
1874 bool literal_element_kinds(
1875 const std::vector<nlohmann::json> &literals,
1876 std::vector<std::vector<typet>> &kinds) const;
1877 bool record_literal_positions(
1878 const std::string &id,
1879 const std::vector<nlohmann::json> &literals,
1880 const std::vector<typet> &kinds);
1881 bool record_literal_elements(
1882 const std::string &id,
1883 const std::vector<nlohmann::json> &literals,
1884 bool positional);
1885 bool mixes_str_and_number(
1886 const std::string &probe,
1887 const std::vector<typet> &kinds);
1888
1889 void handle_array_unpacking(
1890 const nlohmann::json &ast_node,
1891 const nlohmann::json &target,
1892 exprt &rhs,
1893 codet &target_block);
1894
1898 bool
1899 try_tagged_var_assign(const nlohmann::json &ast_node, codet &target_block);
1900
1903 bool module_scope_rhs_needs_type_probe(const nlohmann::json &ast_node);
1904
1908 symbolt *mint_retyped_symbol(
1909 const symbolt &orig,
1910 const std::string &alias_key,
1911 const typet &new_type,
1912 const locationt &location,
1913 const symbol_id &sid,
1914 codet &target_block);
1915
1916 void handle_list_literal_unpacking(
1917 const nlohmann::json &ast_node,
1918 const nlohmann::json &target,
1919 codet &target_block);
1920
1921 void set_assigned_value(symbolt &symbol, const exprt &rhs);
1922 void retype_resized_str(symbolt &symbol, exprt &lhs, exprt &rhs);
1923 bool store_optional_str(symbolt *lhs_symbol, const exprt &lhs, exprt &rhs);
1924
1927 bool annotation_yields_to_rhs(
1928 const nlohmann::json &ast_node,
1929 const exprt &rhs) const;
1930
1931 void handle_assignment_type_adjustments(
1932 symbolt *lhs_symbol,
1933 exprt &lhs,
1934 exprt &rhs,
1935 const std::string &lhs_type,
1936 const nlohmann::json &ast_node,
1937 bool is_ctor_call);
1938
1939 std::string element_kind(const std::string &id) const;
1940 bool element_kinds_differ(const std::string &a, const std::string &b) const;
1944 void propagate_list_type_info(
1945 const exprt &lhs,
1946 const exprt &rhs,
1947 symbolt *lhs_symbol);
1948
1951 void propagate_dict_member_list_type_info(
1952 const exprt &rhs,
1953 const std::string &lhs_identifier);
1954
1955 // =========================================================================
1956 // Dictionary assignment helper methods
1957 // =========================================================================
1958
1970 exprt get_rhs_with_dict_resolution(
1971 const nlohmann::json &ast_node,
1972 const typet &target_type);
1973
1974 // =========================================================================
1975 // Type inference helper methods
1976 // =========================================================================
1977
1988 std::string infer_type_from_any_annotation(
1989 const nlohmann::json &ast_node,
1990 const std::string &lhs_type);
1991
2011 typet resolve_any_subscript_array_type(
2012 const nlohmann::json &ast_node,
2013 const typet &current_type);
2014
2015 typet resolve_call_argument_array_type(
2016 const nlohmann::json &ast_node,
2017 const typet &current_type);
2018
2044 typet resolve_numpy_reducer_call_array_type(
2045 const nlohmann::json &ast_node,
2046 const typet &current_type);
2047
2062 const code_typet *
2063 lambda_call_callee(const nlohmann::json &call, const symbolt &var);
2064 typet resolve_lambda_call_result_type(
2065 const nlohmann::json &ast_node,
2066 const typet &current_type);
2067 // The array type of element-wise arithmetic the annotator typed as a list.
2068 typet resolve_numpy_arithmetic_type(
2069 const nlohmann::json &ast_node,
2070 const exprt &rhs,
2071 const typet &current_type) const;
2072
2073 std::string resolve_name_symbol_id(const std::string &name) const;
2074 exprt
2075 once_bound_exponent(const nlohmann::json &right, const exprt &rhs) const;
2076 symbolt *find_enclosing_scope_symbol(symbol_id sid) const;
2077 symbolt *find_global_symbol(const symbol_id &sid);
2078 bool global_has_type(const std::string &name, const std::string &type) const;
2079 exprt
2080 module_function_expr(const std::string &name, const nlohmann::json &element);
2081 void track_unbound_global(
2082 const std::string &id,
2083 const nlohmann::json &binding,
2084 const typet &type);
2085 void guard_unbound_global(
2086 const std::string &id,
2087 const std::string &name,
2088 const nlohmann::json &element);
2089 void mark_global_bound(const nlohmann::json &stmt, code_blockt &block);
2090 typet forward_function_return_type(const std::string &name, const exprt &fn);
2093 exprt get_default_expr(const nlohmann::json &node);
2094
2095 std::string root_name_from_subscript(const nlohmann::json &node) const;
2096
2097 bool is_basic_numpy_view_subscript(const nlohmann::json &node) const;
2098
2099 // is_basic_numpy_view_subscript(), excluding `.shape[i]`: that indexes the
2100 // plain int tuple `.shape` returns, never the array's own data, so it must
2101 // never be tracked as a numpy view/alias (root_name_from_subscript drills
2102 // through any Attribute to its base Name, so without this exclusion
2103 // `shape_0 = a.shape[0]` would register shape_0 as a view copy of `a`
2104 // itself). A wrapper, not a change to is_basic_numpy_view_subscript
2105 // itself, to keep that already-large function's own decision count as-is.
2106 bool is_tracked_numpy_view_subscript(const nlohmann::json &node) const;
2107
2108 // True for a transpose()/reshape()/ravel()/diagonal() Attribute-call node
2109 // (module or method form), independent of whether its root array name can
2110 // be resolved. Shared by is_numpy_view_copy_expr and
2111 // root_name_from_numpy_view_copy_expr so the view_functions set and the
2112 // Call/Attribute shape check live in one place.
2113 bool is_numpy_view_copy_call_node(const nlohmann::json &node) const;
2114
2115 bool is_numpy_array_constructor_expr(const nlohmann::json &node) const;
2116
2117 // The last direct assignment to `name` in `block[0..end)`, following into
2118 // both arms of a trailing if/else (nullptr unless both arms agree it's a
2119 // numpy array constructor call). Shared by block_assigns_numpy_array_to
2120 // and reject_incompatible_numpy_local_return_branches so both walk the
2121 // same "what did this name last bind to" search -- one only needs to know
2122 // whether it resolved, the other needs the value node itself to compare
2123 // shapes between branches.
2124 const nlohmann::json *find_numpy_ctor_value_assigned_to(
2125 const nlohmann::json &block,
2126 std::size_t end,
2127 const std::string &name) const;
2128
2129 // True when `block[0..end)` ends (directly, or through both arms of a
2130 // trailing if/else) in an assignment binding `name` from a numpy array
2131 // constructor call. Shared by local_var_numpy_array_return's straight-line
2132 // and branching cases so both walk the same "what did this name last bind
2133 // to" search.
2134 bool block_assigns_numpy_array_to(
2135 const nlohmann::json &block,
2136 std::size_t end,
2137 const std::string &name) const;
2138
2139 // True when `func_def`'s only top-level statement is `return <Name>`, and
2140 // that Name was last bound (directly, or identically on both arms of an
2141 // if/else) by a numpy array constructor call. get_function_definition
2142 // checks this before its own return-type dispatch: the static annotator's
2143 // pre-pass already resolved such a Name's own `np.zeros(...)`-shaped
2144 // assignment through the numpy operational model's declared signature
2145 // (`list[float]`) and wrote that bogus annotation into
2146 // `function_node["returns"]` ahead of real conversion -- locking the
2147 // function's return type to a generic PyListObject* before the body (which
2148 // actually returns a concrete array) is ever converted. A direct
2149 // `return np.zeros(...)` never hits this: static inference only chases a
2150 // Name-based callee, not np.zeros's Attribute-based one, so it leaves the
2151 // return type empty and the existing GOTO-scan fallback already types it
2152 // correctly. Treating the local-var case the same way here (by having the
2153 // caller skip the annotation-driven dispatch entirely) reaches that same
2154 // already-correct fallback instead of duplicating it.
2155 bool local_var_numpy_array_return(const nlohmann::json &func_def) const;
2156 // `return np.array(...) * 2`: the annotator types element-wise arithmetic
2157 // over a constructor as a list, so it takes the same fallback.
2158 bool numpy_arithmetic_return(const nlohmann::json &func_def) const;
2159 bool is_numpy_param_operand(
2160 const nlohmann::json &node,
2161 const nlohmann::json &func_def) const;
2162 bool is_numpy_arithmetic_node(
2163 const nlohmann::json &node,
2164 const nlohmann::json &func_def) const;
2165 bool is_numpy_arithmetic_value(
2166 const nlohmann::json &node,
2167 const nlohmann::json &func_def) const;
2168 bool is_numpy_arithmetic_binding(
2169 const nlohmann::json &node,
2170 const nlohmann::json &func_def) const;
2171 bool call_passes_numpy_array(const nlohmann::json &call_node) const;
2172
2173 // The `returns` node get_function_definition's own dispatch should use:
2174 // null when local_var_numpy_array_return applies, function_node["returns"]
2175 // otherwise. Split out to keep the ternary this needs out of
2176 // get_function_definition's own decision count.
2177 const nlohmann::json &
2178 resolve_return_annotation_node(const nlohmann::json &function_node) const;
2179
2180 // Throws an explicit TypeError when local_var_numpy_array_return's
2181 // trailing if/else binds the returned name from a numpy array constructor
2182 // call with a different literal shape argument on each arm -- e.g.
2183 // np.zeros(3) on one branch, np.zeros((2, 2)) on the other. Left
2184 // unchecked, converting the branch merge with two different concrete
2185 // array types crashes value_sett::assign's type-compatibility assertion
2186 // instead of rejecting cleanly (ADR-NP principle 3).
2187 void reject_incompatible_numpy_local_return_branches(
2188 const nlohmann::json &func_def) const;
2189
2190 // True when `func_name`'s own body reads `param_name`'s `.shape`/`.ndim`/
2191 // `.size`/`.T`, or passes it to `numpy.transpose`/`numpy.sort`/
2192 // `numpy.argsort`, *and* some call site feeds the `param_index`-th
2193 // argument from a module-level numpy array constructor call whose shape
2194 // argument is not a literal (e.g. `np.ones(n)` for a variable `n`).
2195 // register_function_argument uses this to reject such a parameter with an
2196 // explicit diagnostic instead of leaving it untyped, which previously
2197 // surfaced as a generic runtime AttributeError the first time the callee
2198 // touched one of those. Deliberately excludes `len()`, which already
2199 // resolves soundly for a symbolic-shape parameter through a different
2200 // path.
2201 bool numpy_param_call_site_has_symbolic_shape(
2202 const std::string &func_name,
2203 size_t param_index,
2204 const std::string &param_name) const;
2205
2206 // Every `Call` node in the AST, computed once and reused:
2207 // register_function_argument calls numpy_param_call_site_has_symbolic_shape
2208 // once per parameter, and each call previously re-walked the entire AST from
2209 // scratch.
2210 const std::vector<numpy_param_call_site> &numpy_call_sites() const;
2211 mutable std::vector<numpy_param_call_site> numpy_call_sites_cache_;
2212 mutable bool numpy_call_sites_cached_ = false;
2213
2214 // True when some top-level statement in `module_body` binds `arg_name` to
2215 // a numpy array constructor call with a non-literal shape. Split out of
2216 // numpy_param_call_site_has_symbolic_shape to keep that function's own
2217 // decision count down.
2218 bool module_level_symbolic_ctor_binding(
2219 const nlohmann::json &module_body,
2220 const std::string &arg_name) const;
2221
2222 // Throws when `numpy_array_param` is false and some call site feeds this
2223 // parameter from a numpy array constructor call with a non-literal shape.
2224 // Split out of register_function_argument to keep the `if` this check
2225 // needs out of that function's own decision count.
2226 void reject_if_symbolic_shape_param(
2227 bool numpy_array_param,
2228 const typet &arg_type,
2229 const std::string &func_name,
2230 size_t param_index,
2231 const std::string &arg_name) const;
2232
2233 // `y = identity(x)`/`y = make()`: a call to a locally-defined function that
2234 // itself returns a numpy array is never an is_numpy_array_constructor_expr
2235 // (that only recognises a literal `np.<ctor>(...)` shape). lhs's own type
2236 // already reflects the array-return fix by the time update_numpy_array_
2237 // binding runs, so trust it instead of duplicating that resolution here.
2238 // Split out of update_numpy_array_binding to keep its own decision count
2239 // from growing further.
2240 bool is_numpy_arithmetic_result(
2241 const nlohmann::json &rhs_node,
2242 const exprt &lhs) const;
2243 bool is_array_returning_call_expr(
2244 const nlohmann::json &rhs_node,
2245 const exprt &lhs) const;
2246
2247 bool is_numpy_view_copy_expr(const nlohmann::json &node) const;
2248
2249 std::string
2250 root_name_from_numpy_view_copy_expr(const nlohmann::json &node) const;
2251
2252 bool contains_tracked_numpy_view_name(const nlohmann::json &node);
2253
2254 bool is_tracked_numpy_view_name_node(const nlohmann::json &node);
2255
2256 bool is_basic_numpy_view_subscript_escape(const nlohmann::json &node);
2259 exprt probe_expr(const nlohmann::json &node);
2260 std::optional<typet>
2261 literal_numpy_array_type(const nlohmann::json &call) const;
2262 nlohmann::json bind_numpy_constructor_argument(const nlohmann::json &arg);
2263
2264 bool contains_tracked_numpy_view_object(const nlohmann::json &node);
2265
2266 void reject_numpy_view_mutating_method_call(const nlohmann::json &node);
2267
2270 std::string numpy_view_storage_root(const std::string &id) const;
2271 bool is_numpy_storage_escaped(const nlohmann::json &name) const;
2272 bool is_closed_return_expression(
2273 const nlohmann::json &value,
2274 const nlohmann::json &params) const;
2275 std::optional<nlohmann::json>
2276 simple_call_return_value(const nlohmann::json &call) const;
2280 std::optional<nlohmann::json>
2281 fold_numpy_view_call(const nlohmann::json &call);
2284 void
2285 get_folded_var_assign(const nlohmann::json &ast_node, codet &target_block);
2289 void reject_or_defer_numpy_view_return(
2290 const nlohmann::json &ast_node,
2291 codet &target_block);
2292 bool bind_numpy_pointer_view_alias(
2293 const exprt &lhs,
2294 const std::string &lhs_id,
2295 const std::string &rhs_id);
2296 void reject_multi_path_numpy_view_return(const nlohmann::json &call);
2297 bool numpy_subscript_yields_view(const nlohmann::json &node) const;
2298 bool holds_numpy_view(const nlohmann::json &node) const;
2299 bool is_numpy_module_call(const nlohmann::json &node) const;
2300 bool is_numpy_view_value(const nlohmann::json &node) const;
2301 void reject_numpy_view_comprehension(const nlohmann::json &node) const;
2304 void check_numpy_view_statement(const nlohmann::json &statement) const;
2305 void reject_unfoldable_numpy_view_call(const nlohmann::json &call);
2306 bool reject_or_defer_numpy_view_name_return(
2307 const nlohmann::json &ast_node,
2308 codet &target_block);
2309 nlohmann::json current_user_function_node() const;
2310 bool is_numpy_module_param(const std::string &root_name) const;
2311 bool is_copied_numpy_view_local(const std::string &name) const;
2312 bool is_scalar_read_of_numpy_view_param(
2313 const exprt &lhs,
2314 const std::string &storage_id) const;
2315 code_blockt *while_condition_block(
2316 const nlohmann::json &ast_node,
2317 code_blockt &cond_prelude);
2318 void reject_live_numpy_view_copies_of(const nlohmann::json &args);
2319 bool passes_numpy_view(const nlohmann::json &arg);
2320 bool is_scalar_numpy_view_call(const nlohmann::json &call);
2321 bool passes_unnamed_numpy_view_argument(const nlohmann::json &call);
2322 bool contains_unnamed_numpy_view_argument(const nlohmann::json &node);
2323 const nlohmann::json &hoist_unnamed_numpy_view_arguments(
2324 const nlohmann::json &statement,
2325 nlohmann::json &rewritten,
2326 codet &target_block);
2327 nlohmann::json bind_numpy_view_temporary(
2328 const nlohmann::json &statement,
2329 const nlohmann::json &value,
2330 const std::string &prefix,
2331 codet &target_block);
2332 bool hoist_numpy_view_arguments(
2333 const std::string &key,
2334 nlohmann::json &rewritten,
2335 codet &target_block);
2336 bool needs_numpy_view_call_binding(const nlohmann::json &node);
2337 std::string numpy_view_callee_name(const symbol_id &function) const;
2338 std::optional<std::pair<std::string, std::size_t>>
2339 numpy_view_method_callee(const nlohmann::json &call) const;
2340 bool binds_every_numpy_view_argument(const nlohmann::json &call);
2341 bool names_python_builtin(const std::string &name) const;
2342 bool consumes_numpy_view_as_list(const nlohmann::json &node) const;
2343 bool is_builtin_over_numpy_view(const nlohmann::json &node) const;
2344 symbolt *find_symbol_in_import(
2345 const nlohmann::json &obj,
2346 const std::string &symbol_id,
2347 const std::string &lookup_name) const;
2348 symbolt *find_symbol_in_module(
2349 const std::string &symbol_id,
2350 const std::string &module_file,
2351 const std::string &lookup_name,
2352 const std::string &name) const;
2353 bool import_hides_builtin(
2354 const nlohmann::json &import,
2355 const std::string &symbol_id,
2356 const std::string &name) const;
2357 bool needs_fresh_retype_slot(
2358 const exprt &lhs,
2359 const exprt &rhs,
2360 const std::string &lhs_id) const;
2361 bool is_numpy_array_to_view_rebind(
2362 const exprt &lhs,
2363 const exprt &rhs,
2364 const std::string &lhs_id) const;
2365 std::string pointee_class(const typet &type) const;
2366 void retype_for_class_rebind(
2367 const nlohmann::json &target,
2368 const nlohmann::json &ast_node,
2369 bool is_ctor_call,
2370 const symbol_id &sid,
2371 const locationt &location,
2372 symbolt *&lhs_symbol,
2373 exprt &lhs,
2374 codet &target_block);
2375 void
2376 reject_numpy_array_retype(const symbolt &symbol, const typet &type) const;
2377 bool needs_fresh_numpy_array_slot(
2378 const exprt &lhs,
2379 const exprt &rhs,
2380 const std::string &lhs_id) const;
2381 bool is_numpy_array_reshape_rebind(
2382 const exprt &lhs,
2383 const exprt &rhs,
2384 const std::string &lhs_id) const;
2385 bool passes_numpy_view_anywhere(const nlohmann::json &call);
2386 bool is_handled_numpy_view_call(const nlohmann::json &call);
2387 bool is_attribute_store_of_numpy_view(
2388 const nlohmann::json &target,
2389 const nlohmann::json &value);
2390 bool call_needs_view_argument_hoist(const nlohmann::json &call);
2391 bool takes_numpy_view_argument(const nlohmann::json &call, std::size_t index);
2392 bool is_rank1_numpy_view(const nlohmann::json &node) const;
2393 bool is_rank1_numpy_array_name(const nlohmann::json &node) const;
2394 void reject_builtin_over_complex_array(const nlohmann::json &node) const;
2395 bool is_foldable_constant_index(const exprt &expr) const;
2396 bool adapt_numpy_view_builtin_arguments(nlohmann::json &node);
2397 std::optional<nlohmann::json>
2398 inline_numpy_view_lambda_call(const nlohmann::json &call);
2399 bool is_inlined_numpy_view_lambda(const nlohmann::json &statement);
2400 std::optional<bool> bind_lambda_arguments(
2401 const nlohmann::json &signature,
2402 const nlohmann::json &args,
2403 std::map<std::string, nlohmann::json> &values) const;
2404 std::set<std::string> numpy_inlined_lambdas_;
2405 const nlohmann::json &adapt_numpy_view_builtin_calls(
2406 const nlohmann::json &statement,
2407 nlohmann::json &rewritten);
2408 bool split_conditional_numpy_view_assignment(
2409 const nlohmann::json &statement,
2410 nlohmann::json &rewritten);
2411 bool needs_numpy_view_hoist(const nlohmann::json &node);
2412 bool freeze_numpy_view_operand(
2413 const nlohmann::json::json_pointer &path,
2414 nlohmann::json &rewritten,
2415 codet &target_block);
2416 bool hoist_first_evaluated_numpy_view_call(
2417 const nlohmann::json::json_pointer &path,
2418 bool skip,
2419 nlohmann::json &rewritten,
2420 codet &target_block);
2421 std::size_t numpy_view_arg_count_ = 0;
2424 bool returns_bound_numpy_view_param(const nlohmann::json &func_node);
2426 const nlohmann::json *
2427 returned_numpy_view_argument(const nlohmann::json &call);
2428 bool try_bind_returned_numpy_view_param(
2429 const nlohmann::json &ast_node,
2430 codet &target_block);
2432 const nlohmann::json *numpy_discarded_call_ = nullptr;
2433 void reject_numpy_view_argument_use(const nlohmann::json &call);
2434 void reject_numpy_view_method_call(const nlohmann::json &func) const;
2435 void reject_numpy_view_callee(const nlohmann::json &call);
2436 void reject_inline_runtime_numpy_slice(const nlohmann::json &call) const;
2437 void reject_numpy_view_container_store(const nlohmann::json &ast_node);
2438 bool is_numpy_view_syntax(
2439 const nlohmann::json &value,
2440 const std::string &scope,
2441 std::size_t depth) const;
2442 bool is_numpy_storage_syntax(
2443 const nlohmann::json &value,
2444 const std::string &scope,
2445 std::size_t depth) const;
2446 bool is_fold_only_numpy_function(const nlohmann::json &function_node);
2448 void get_unfolded_function_definition(const nlohmann::json &function_node);
2450 void track_numpy_view_call_escape(const nlohmann::json &call);
2451 void reject_escaped_numpy_view_read(const nlohmann::json &node) const;
2452 void reject_escaped_numpy_view_write(const nlohmann::json &target) const;
2455 void reject_escaped_numpy_view_use(const nlohmann::json &statement) const;
2456
2457 void reject_numpy_view_identity_query(const nlohmann::json &node);
2458
2459 void reject_copied_numpy_view_in_container(
2460 const nlohmann::json &ast_node,
2461 const std::set<std::string> &container_types);
2462
2463 nlohmann::json
2464 get_ravel_receiver_node(const nlohmann::json &ravel_call) const;
2465 bool is_numpy_ravel_receiver(const nlohmann::json &ravel_call) const;
2466 nlohmann::json
2467 flat_subscript_receiver_node(const nlohmann::json &subscript_node) const;
2468 bool try_handle_flat_index_assignment(
2469 const nlohmann::json &ast_node,
2470 const nlohmann::json &target,
2471 codet &target_block);
2472 std::optional<exprt> try_build_flat_index_read(const nlohmann::json &element);
2473
2474 // ExpressionType::SUBSCRIPT's handler, split out of get_expr into its own
2475 // function plus these sub-dispatch helpers -- each phase of a[...]'s
2476 // handling (base resolution, dict/tuple pointer unwrap, and one dispatch
2477 // per index shape: tuple, dict, bool-mask-rows, multi-axis tuple, fancy
2478 // list, bool-mask variable, __getitem__) is independently a return early
2479 // or fall-through step, so extracting them keeps every one individually
2480 // simple instead of one function accumulating get_expr's own decision
2481 // count as ADR-NP-003 etapa 2 adds more index shapes.
2482 exprt handle_subscript_expr(const nlohmann::json &element);
2483 std::optional<exprt>
2484 resolve_subscript_base(const nlohmann::json &element, exprt &array);
2485 std::optional<exprt> try_fold_constant_string_slice(
2486 const nlohmann::json &element,
2487 const exprt &array);
2488 void unwrap_subscript_base_types(
2489 exprt &array,
2490 typet &array_type,
2491 typet &array_type_for_dict,
2492 bool &array_is_dict_pointer,
2493 const nlohmann::json &element);
2494 std::optional<exprt> try_dispatch_tuple_subscript(
2495 const exprt &array,
2496 const typet &array_type,
2497 const nlohmann::json &slice,
2498 const nlohmann::json &element);
2499 std::optional<exprt> try_dispatch_dict_subscript(
2500 exprt &array,
2501 const typet &array_type_for_dict,
2502 bool array_is_dict_pointer,
2503 const nlohmann::json &element);
2504 bool subscript_targets_list_model(
2505 const typet &array_type,
2506 const typet &list_type) const;
2507 std::optional<exprt> try_dispatch_multidim_tuple_index(
2508 const exprt &array,
2509 const typet &array_type,
2510 const nlohmann::json &slice,
2511 const nlohmann::json &element,
2512 bool tuple_index_targets_list_model,
2513 const typet &list_type);
2514 std::optional<exprt> try_dispatch_multidim_tuple_axes(
2515 const exprt &array,
2516 const nlohmann::json &element,
2517 const std::vector<nlohmann::json> &idx_nodes);
2518 std::optional<exprt> try_dispatch_chained_axis_index(
2519 const exprt &array,
2520 const nlohmann::json &element,
2521 const std::vector<nlohmann::json> &idx_nodes,
2522 const typet &list_type);
2523 std::optional<exprt> try_dispatch_fancy_list_index(
2524 const exprt &array,
2525 const nlohmann::json &slice,
2526 const nlohmann::json &element,
2527 bool tuple_index_targets_list_model);
2528 std::optional<exprt> try_dispatch_bool_mask_variable_index(
2529 const exprt &array,
2530 const typet &array_type,
2531 const nlohmann::json &slice,
2532 const nlohmann::json &element,
2533 bool tuple_index_targets_list_model);
2534 std::optional<exprt> try_dispatch_fancy_index_via_list_variable(
2535 const exprt &array,
2536 const nlohmann::json &slice,
2537 const nlohmann::json &element);
2538 std::optional<exprt> try_dispatch_dunder_getitem(
2539 const nlohmann::json &element,
2540 const nlohmann::json &slice);
2541 void reject_scalar_subscript(
2542 const typet &array_type,
2543 const nlohmann::json &element) const;
2544
2545 std::optional<nlohmann::json>
2546 select_return_value_for_call(const nlohmann::json &call_node) const;
2547
2548 nlohmann::json substitute_call_arguments(
2549 const nlohmann::json &node,
2550 const nlohmann::json &call_node) const;
2551
2552 bool return_value_uses_call_argument(
2553 const nlohmann::json &return_value,
2554 const nlohmann::json &call_node) const;
2555
2556 // return <call>(<param>, ...), e.g. `def transposed(a): return
2557 // np.transpose(a)`: true when every Name the call expression references is
2558 // either one of `params` or an imported module alias. Split out of
2559 // return_value_uses_call_argument to keep that function's own decision
2560 // count down.
2561 bool return_call_only_references_params_or_modules(
2562 const nlohmann::json &return_value,
2563 const nlohmann::json &params) const;
2564
2565 void reject_unsafe_numpy_view_target(const nlohmann::json &target);
2566 void reject_unsafe_numpy_view_write_to(const std::string &root_id);
2567
2568 void reject_numpy_view_slice_assignment(const nlohmann::json &target);
2569
2572 bool reject_immutable_item_assignment(
2573 const typet &container_type,
2574 codet &target_block);
2575
2576 void record_numpy_view_copy(const exprt &lhs, const nlohmann::json &rhs_node);
2577 std::string numpy_view_source_of(const std::string &storage_id) const;
2578
2579 bool is_tracked_numpy_view_id(const std::string &symbol_id) const;
2580
2581 void reject_nonconstant_numpy_view_write(const nlohmann::json &target) const;
2582
2583 std::optional<std::vector<nlohmann::json>>
2584 build_numpy_nditer_logical_elements(const nlohmann::json &arg) const;
2585
2586 std::optional<std::pair<std::vector<std::size_t>, std::vector<exprt>>>
2587 build_numpy_descriptor_materialized_elements(
2588 const nlohmann::json &arg,
2589 const std::string &unsupported_rank_error);
2590
2591 std::optional<std::vector<std::size_t>>
2592 get_empty_numpy_literal_slice_shape(const nlohmann::json &arg) const;
2593
2594 std::optional<exprt> build_numpy_descriptor_materialized_list(
2595 const nlohmann::json &arg,
2596 bool nested);
2597
2600 bool numpy_result_is_fresh_copy_ = false;
2602 bool numpy_result_is_view_ = false;
2603
2605 bool is_numpy_param_slice(const nlohmann::json &subscript) const;
2606
2608 exprt hoist_numpy_element(const exprt &element);
2609
2611 exprt materialize_numpy_elements(
2612 const nlohmann::json &location_node,
2613 const std::vector<std::size_t> &shape,
2614 const std::vector<exprt> &elems,
2615 const typet &elem_type);
2616
2618 std::optional<exprt> build_numpy_descriptor_materialized_array(
2619 const nlohmann::json &arg,
2620 const std::vector<std::size_t> *reshape_to = nullptr);
2621
2622 std::optional<std::vector<std::size_t>>
2623 get_numpy_nditer_logical_shape(const std::string &root_id) const;
2624
2625 std::optional<typet>
2626 get_numpy_descriptor_element_type(const std::string &root_id) const;
2627
2628 bool is_numpy_readonly_view_arg(const nlohmann::json &arg) const;
2629
2630 void clear_numpy_view_copy(const exprt &lhs);
2631
2632 void
2633 update_numpy_array_binding(const exprt &lhs, const nlohmann::json &rhs_node);
2634
2635 bool update_numpy_array_binding_from_name(
2636 const exprt &lhs,
2637 const std::string &lhs_id,
2638 const nlohmann::json &rhs_node,
2639 bool unconditional_assignment);
2640
2641 bool preserve_conditional_numpy_alias_shape(
2642 const std::string &lhs_id,
2643 const std::string &rhs_id,
2644 bool unconditional_assignment);
2645
2646 void copy_numpy_alias_shape_state(
2647 const std::string &lhs_id,
2648 const std::string &rhs_id);
2649
2650 void reject_conditional_numpy_alias_rebind(
2651 const exprt &lhs,
2652 const nlohmann::json &rhs_node) const;
2653
2654 bool record_numpy_view_copy_from_returned_argument(
2655 const exprt &lhs,
2656 const std::string &lhs_id,
2657 const nlohmann::json &rhs_node);
2658
2659 void clear_numpy_array_storage_aliases_for(const std::string &symbol_id);
2660
2661 void bind_numpy_array_storage_alias(
2662 const std::string &lhs_id,
2663 const std::string &rhs_id);
2664
2665 symbolt *resolve_numpy_array_storage_alias(symbolt *symbol) const;
2666
2667 std::string
2668 resolve_numpy_array_storage_alias_id(const std::string &symbol_id) const;
2669
2676 std::vector<std::string> numpy_views_of(const std::string &rebound_id) const;
2677
2678 bool keep_numpy_result_view(const std::string &lhs_id);
2679 bool is_readonly_numpy_view_expr(const nlohmann::json &node) const;
2680
2681 void record_numpy_constructor_binding(
2682 const exprt &lhs,
2683 const std::string &lhs_id,
2684 const nlohmann::json &rhs_node,
2685 bool unconditional_assignment);
2686
2687 void detach_numpy_pointer_views_of(
2688 const std::string &rebound_id,
2689 const locationt &location,
2690 codet &target_block);
2691
2693 void detach_numpy_pointer_view(
2694 const std::string &view_id,
2695 const locationt &location,
2696 codet &target_block);
2697
2700 void share_numpy_storage_snapshot(
2701 const std::string &storage_id,
2702 const std::vector<std::string> &view_ids,
2703 const locationt &location,
2704 codet &target_block,
2705 const std::string &heir_id = "");
2706 std::vector<std::string>
2707 numpy_storage_aliases_of(const std::string &rebound_id) const;
2708 std::string hand_numpy_storage_to_alias(
2709 const std::string &rebound_id,
2710 const locationt &location,
2711 codet &target_block);
2712
2713 bool should_rebuild_cached_numpy_row_subscript_rhs(
2714 const nlohmann::json &rhs_node) const;
2715
2716 bool is_tracked_2d_numpy_array_symbol(const std::string &source_id) const;
2717
2718 std::optional<nlohmann::json>
2719 rewrite_numpy_method_call_node(const nlohmann::json &call_node) const;
2720 bool is_numpy_subscript_reducer_receiver(
2721 const nlohmann::json &method_base,
2722 const std::string &method_name) const;
2723
2724 // get_var_assign's RHS preprocessing step: rewrites `a.T` into
2725 // `np.transpose(a)` (numpy's own Attribute-shaped transpose sugar, with
2726 // no method-call node to reach rewrite_numpy_method_call_node through),
2727 // or else defers to rewrite_numpy_method_call_node for any other numpy
2728 // method-call RHS. Split out to keep get_var_assign's own decision count
2729 // from growing as more special-cased RHS rewrites land there.
2730 nlohmann::json rewrite_assign_rhs_node(const nlohmann::json &ast_node) const;
2731 nlohmann::json numpy_transpose_base(const nlohmann::json &node) const;
2732
2733 // Classifies a Call node as a numpy method call: (is_a_method_call,
2734 // method_name, method_base, is_a_supported_copy_method,
2735 // is_a_supported_dispatch_rewrite_method). Split out of
2736 // rewrite_numpy_method_call_node() to keep that function's own decision
2737 // count low.
2738 std::tuple<bool, std::string, nlohmann::json, bool, bool>
2739 classify_numpy_method_call(const nlohmann::json &call_node) const;
2740
2741 bool
2742 method_base_is_imported_module(const std::string &method_base_name) const;
2743
2744 bool
2745 method_base_is_tracked_numpy_array(const std::string &method_base_name) const;
2746
2747 // Builds the np.<method_name>(method_base, ...original args...) rewrite of
2748 // a recognized numpy method call.
2749 nlohmann::json build_numpy_method_rewrite_node(
2750 const nlohmann::json &call_node,
2751 const std::string &method_name,
2752 const nlohmann::json &method_base) const;
2753
2754 // =========================================================================
2755 // Unpacking helper methods
2756 // =========================================================================
2757
2769 bool handle_unpacking_assignment(
2770 const nlohmann::json &ast_node,
2771 const nlohmann::json &target,
2772 codet &target_block);
2773
2774 bool unpack_record_is_trusted(const nlohmann::json &value) const;
2775
2780 void unpack_nested_target(
2781 const nlohmann::json &ast_node,
2782 const nlohmann::json &target,
2783 const exprt &value,
2784 codet &target_block);
2785
2786 exprt hold_tuple_member_list(
2787 const nlohmann::json &ast_node,
2788 const exprt &value,
2789 codet &target_block);
2790
2799 void desugar_unpacking_with_lvalue_targets(
2800 const nlohmann::json &ast_node,
2801 const nlohmann::json &target,
2802 codet &target_block);
2803
2804 // =========================================================================
2805 // Symbol creation helper methods
2806 // =========================================================================
2807
2820 symbolt *create_symbol_for_unannotated_assign(
2821 const nlohmann::json &ast_node,
2822 const nlohmann::json &target,
2823 const symbol_id &sid,
2824 bool is_global);
2825
2832 bool is_global_variable(const symbol_id &sid) const;
2833
2836 void declare_nonlocal(const nlohmann::json &element);
2837
2840 void redirect_nonlocal(symbol_id &sid) const;
2841
2851 std::string extract_target_name(const nlohmann::json &target) const;
2852
2853 // =========================================================================
2854 // RHS processing helper methods
2855 // =========================================================================
2856
2859 static const nlohmann::json *
2860 reordering_builtin_arg(const nlohmann::json &ast_node);
2861
2862 void copy_elem_types_from_reordering_builtin(
2863 const nlohmann::json &ast_node,
2864 const std::string &lhs_id);
2865
2880 std::string user_class_of(const typet &type);
2881 void reject_attribute_added_on_some_paths(
2882 const std::string &receiver,
2883 const std::string &class_name,
2884 const std::string &attr) const;
2885 void reject_attribute_scalar_change(const exprt &lhs, const exprt &rhs);
2886 void reject_attribute_class_change(
2887 const exprt &lhs,
2888 const exprt &rhs,
2889 const nlohmann::json &ast_node,
2890 bool is_ctor_call);
2891 void widen_int_target_for_float_call(
2892 exprt &lhs,
2893 const exprt &rhs,
2894 bool is_ctor_call);
2895 void handle_function_call_rhs(
2896 const nlohmann::json &ast_node,
2897 symbolt *lhs_symbol,
2898 exprt &lhs,
2899 exprt &rhs,
2900 const locationt &location,
2901 bool is_ctor_call,
2902 codet &target_block);
2903
2904 void wrap_call_result_in_optional(
2905 const nlohmann::json &ast_node,
2906 const exprt &lhs,
2907 exprt &rhs,
2908 const locationt &location,
2909 codet &target_block);
2910
2922 exprt handle_string_literal_rhs(
2923 const nlohmann::json &ast_node,
2924 const std::string &lhs_type,
2925 const exprt &rhs);
2926
2927 // =========================================================================
2928 // Helper methods for binary operator expression handling
2929 // =========================================================================
2930
2946 exprt handle_type_identity_check(
2947 const std::string &op,
2948 const exprt &lhs,
2949 const exprt &rhs,
2950 const nlohmann::json &left,
2951 const nlohmann::json &right);
2952
2954 exprt handle_type_comparison(
2955 const std::string &op,
2956 const exprt &lhs,
2957 const exprt &rhs,
2958 const nlohmann::json &left,
2959 const nlohmann::json &right);
2960
2961 exprt erased_type_argument(const nlohmann::json &node);
2962
2965 static constexpr const char *unknown_class_name = "<unknown class>";
2966
2969 exprt handle_erased_type_comparison(
2970 const std::string &op,
2971 const nlohmann::json &left,
2972 const nlohmann::json &right);
2973
2977 std::optional<std::string>
2978 class_identity_operand(const nlohmann::json &node, const exprt &expr) const;
2979
2983 exprt handle_tagged_scalar_binop(
2984 const std::string &op,
2985 const exprt &lhs,
2986 const exprt &rhs,
2987 const nlohmann::json &left,
2988 const nlohmann::json &right,
2989 const nlohmann::json &element);
2990
2993 exprt handle_dict_bitwise(
2994 const std::string &op,
2995 const exprt &lhs,
2996 const exprt &rhs,
2997 const nlohmann::json &element);
2998
2999 exprt
3000 build_emptiness_check(const exprt &value, const nlohmann::json &element);
3001
3004 static void convert_function_call_to_side_effect(exprt &expr);
3005
3011 void convert_function_calls_to_side_effects(exprt &lhs, exprt &rhs);
3012
3019 exprt handle_chained_comparisons_logic(
3020 const nlohmann::json &element,
3021 exprt &bin_expr);
3022
3025 std::pair<exprt, exprt> chained_pair_operands(
3026 const nlohmann::json &element,
3027 size_t i,
3028 exprt &first_pair,
3029 exprt &reuse);
3030
3035 exprt bind_chained_comparator(
3036 const exprt &operand,
3037 const nlohmann::json &element,
3038 exprt &reuse);
3039
3043 exprt bind_operand_read_twice(
3044 const exprt &operand,
3045 const nlohmann::json &element,
3046 exprt &reread);
3047
3059 bool handle_none_check_setup(
3060 const std::string &op,
3061 const exprt &lhs,
3062 const exprt &rhs);
3063
3078 exprt numpy_array_arithmetic(
3079 const std::string &op,
3080 const exprt &lhs,
3081 const exprt &rhs,
3082 const locationt &location);
3083 void
3084 guard_negative_exponents(const exprt &exponents, const locationt &location);
3085 exprt numpy_elementwise(
3086 const std::string &op,
3087 const exprt &lhs,
3088 const exprt &rhs,
3089 const typet &type);
3090 exprt raise_in_expression(
3091 const std::string &exception,
3092 const std::string &message,
3093 const typet &type);
3094 void reject_unmodelled_array_arithmetic(
3095 const std::string &op,
3096 const exprt &lhs,
3097 const exprt &rhs,
3098 const nlohmann::json &element);
3099 exprt
3100 numpy_float_remainder(const exprt &x, const exprt &y, const typet &type);
3101 exprt numpy_element_op(
3102 const std::string &op,
3103 const exprt &x,
3104 const exprt &y,
3105 const typet &type);
3106 exprt handle_array_operations(
3107 const std::string &op,
3108 exprt &lhs,
3109 exprt &rhs,
3110 const nlohmann::json &left,
3111 const nlohmann::json &right,
3112 const nlohmann::json &element);
3113
3117 exprt build_bytes_concat(const exprt &lhs, const exprt &rhs);
3118
3119 // A right operand of list + that is never a list: a scalar, a str, or a
3120 // tuple outside `+=` (which extends the list).
3121 bool is_definite_non_list_addend(
3122 const typet &type,
3123 const nlohmann::json &element) const;
3124
3138 exprt handle_list_operations(
3139 const std::string &op,
3140 exprt &lhs,
3141 exprt &rhs,
3142 const nlohmann::json &left,
3143 const nlohmann::json &right,
3144 const nlohmann::json &element);
3145
3157 exprt handle_relational_type_mismatches(
3158 const std::string &op,
3159 exprt &lhs,
3160 exprt &rhs,
3161 const nlohmann::json &element);
3162
3176 exprt handle_string_binary_operations(
3177 const std::string &op,
3178 exprt &lhs,
3179 exprt &rhs,
3180 const nlohmann::json &left,
3181 const nlohmann::json &right,
3182 const nlohmann::json &element);
3183
3186 exprt str_pointer_add_error(
3187 const std::string &op,
3188 const exprt &lhs,
3189 const exprt &rhs,
3190 const nlohmann::json &left,
3191 const nlohmann::json &right);
3192
3204 exprt build_binary_expression(const std::string &op, exprt &lhs, exprt &rhs);
3205
3213 typet infer_return_type_from_body(const nlohmann::json &body);
3214
3215 // =========================================================================
3216 // String method helpers
3217 // =========================================================================
3218
3219 exprt handle_string_type_mismatch(
3220 const exprt &lhs,
3221 const exprt &rhs,
3222 const std::string &op);
3223
3224 void process_forward_reference(
3225 const nlohmann::json &annotation,
3226 codet &target_block);
3227
3228 // Build the class a `tag-<Name>` symbol type refers to when it is defined
3229 // later in the module, so the type can be followed.
3230 void build_forward_class(const typet &type);
3231
3232 // =========================================================================
3233 // Optional type helpers
3234 // =========================================================================
3235
3237 typet optional_return_type(
3238 const nlohmann::json &function_node,
3239 const typet &declared);
3240 exprt wrap_in_optional(const exprt &value, const typet &optional_type);
3242 exprt wrap_if_optional(const exprt &value, const typet &type)
3243 {
3244 return type_utils::is_optional_struct(type) ? wrap_in_optional(value, type)
3245 : value;
3246 }
3249 exprt wrap_stored_if_optional(const exprt &value, const typet &type);
3250 typet optional_ternary_type(exprt &then, exprt &else_expr, bool then_is_none);
3251 exprt get_return_value(const nlohmann::json &value);
3252 typet subscript_annotation_type(
3253 const std::string &base,
3254 const nlohmann::json &var_node);
3255
3256 // =========================================================================
3257 // Enum support helpers
3258 // =========================================================================
3259
3262 exprt make_enum_member_struct_expr(
3263 const symbolt &int_sym,
3264 const std::string &class_name,
3265 const std::string &member_name);
3266
3267 void adopt_tagged_element(symbolt *lhs_symbol, exprt &lhs, const exprt &rhs);
3268
3269 void adopt_array_type(symbolt &lhs_symbol, exprt &lhs, exprt &rhs);
3270
3272 exprt materialize_optional(const exprt &expr, const nlohmann::json &element);
3273 exprt check_float_fits_int_return(
3274 const nlohmann::json &ast_node,
3275 const exprt &value,
3276 codet &target_block);
3278 static exprt string_literal_address(const exprt &array);
3279 void
3280 decay_string_literal_returns(exprt &node, const typet &return_type) const;
3281 exprt coerce_optional_return(
3282 const exprt &value,
3283 const locationt &location,
3284 codet &target_block);
3285 exprt narrow_optional_return(
3286 const exprt &value,
3287 const locationt &location,
3288 codet &target_block);
3289 exprt resolve_optional_operands(
3290 const std::string &op,
3291 exprt &lhs,
3292 exprt &rhs,
3293 const nlohmann::json &element,
3294 bool is_none_check);
3295 exprt unwrap_optional_if_needed(
3296 const exprt &expr,
3297 const nlohmann::json &element = nlohmann::json());
3298
3299 // =========================================================================
3300 // Dunder method dispatch for user-defined struct types
3301 // =========================================================================
3302
3303 static std::string op_to_dunder(const std::string &op);
3304 static std::string op_to_rdunder(const std::string &op);
3306 exprt apply_bool_dunder(exprt cond, const locationt &location);
3307
3309 exprt fold_tagged_identity(
3310 const std::string &op,
3311 const exprt &lhs,
3312 const exprt &rhs,
3313 const nlohmann::json &left,
3314 const nlohmann::json &right);
3315
3317 exprt tagged_truthiness(exprt value, const nlohmann::json &node);
3318
3320 exprt handle_tagged_unary_operator(
3321 const std::string &op,
3322 const exprt &operand,
3323 const nlohmann::json &element);
3324
3326 void refuse_tagged_boolop_operand(const exprt &operand) const;
3327
3330 exprt apply_string_truthiness(const exprt &str, const locationt &location);
3331
3333 exprt apply_bool_dunder_for_not(
3334 const std::string &op,
3335 exprt operand,
3336 const locationt &location);
3337
3338 symbolt *find_dunder_method(
3339 const std::string &class_name,
3340 const std::string &dunder_name);
3341
3344 std::string instance_class_name(const nlohmann::json &value_node);
3345
3348 bool is_class_instance(const nlohmann::json &value_node);
3349 bool has_dunder_method(
3350 const nlohmann::json &value_node,
3351 const std::string &dunder_name);
3352 exprt dispatch_dunder_operator(
3353 const std::string &op,
3354 exprt &lhs,
3355 exprt &rhs,
3356 const locationt &loc);
3357 exprt dispatch_unary_dunder_operator(
3358 const std::string &op,
3359 exprt &operand,
3360 const locationt &loc);
3361
3362 // =========================================================================
3363 // Member variables
3364 // =========================================================================
3365
3366 contextt &symbol_table_;
3367 const nlohmann::json *ast_json;
3372 const nlohmann::json *entry_ast_;
3376 const std::vector<nlohmann::json> *extra_asts_;
3377 const global_scope &global_scope_;
3378 type_handler type_handler_;
3379 element_type_registry element_type_registry_;
3380 std::vector<std::function<void()>> deferred_checks_;
3381 string_builder *string_builder_;
3382 symbol_generator sym_generator_;
3383
3384 namespacet ns;
3385 typet current_element_type;
3386 typet current_func_return_type_;
3388 bool current_func_annotated_int_ = false;
3391 typet ternary_return_target_;
3392 std::string main_python_file;
3393 std::string current_python_file;
3394 size_t not_callable_count_ = 0;
3395 nlohmann::json imported_module_json;
3396 std::string current_func_name_;
3397 std::string current_class_name_;
3398 std::size_t get_expr_depth_ = 0;
3399 code_blockt *current_block;
3400 exprt *current_lhs;
3403 std::array<const nlohmann::json *, 2> type_compared_operands_{};
3404 string_handler string_handler_;
3405 python_math math_handler_;
3406 complex_handler complex_handler_;
3407 dynamic_type_handler dynamic_type_handler_;
3408 tuple_handler *tuple_handler_;
3409 python_dict_handler *dict_handler_;
3410 python_typechecking *typechecker_ = nullptr;
3411 python_lambda *lambda_handler_;
3412 python_exception_handler *exception_handler_;
3413
3414 bool is_converting_lhs = false;
3415 bool is_converting_rhs = false;
3416
3417 // The assignment target node currently being converted, or null. Reads
3418 // nested inside a target -- the index in `xs[idx[0]] = v`, the base in
3419 // `xs[0][1] = v` -- are converted with is_converting_lhs set too, so only
3420 // node identity picks out the slot actually being stored to.
3421 const nlohmann::json *lhs_store_target_ = nullptr;
3422
3425 bool is_store_target(const nlohmann::json &node) const
3426 {
3427 return is_converting_lhs && lhs_store_target_ == &node;
3428 }
3429 // The ZeroDivisionError guard (and its divisor hoist) must be emitted only
3430 // where the division is really code-generated in its execution context.
3431 // Keep it inside a lambda body converted at its definition (the enclosing
3432 // block is still current) and suppress it during the discarded type-probe
3433 // pass of an assignment RHS (which would otherwise emit the guard twice as
3434 // dead code and evaluate a side-effecting divisor an extra time).
3435 bool converting_defaults_ = false;
3436 bool converting_lambda_body_ = false;
3437 std::map<std::string, irep_idt> lambda_copies_;
3438 bool in_rhs_type_probe_ = false;
3439 // Set while probe_expr() evaluates a node only to inspect its result.
3440 bool in_scratch_probe_ = false;
3441 // A clause is a specification, not code: converting one must not plant a
3442 // statement into the enclosing block. The guard did, so annotating a file
3443 // changed its verification result with contracts switched off, and a `//` in
3444 // a loop invariant raised inside the loop body. C emits nothing from a
3445 // clause either.
3446 bool in_contract_clause_ = false;
3447 bool in_lazy_operand_ = false;
3448 // Number of try bodies enclosing the statement being converted.
3449 unsigned try_body_depth_ = 0;
3450 // The test of the assert statement being converted; see
3451 // lower_short_circuit_boolop.
3452 const nlohmann::json *asserted_test_ = nullptr;
3453
3454 bool needs_zero_division_guard(const std::string &op, const exprt &rhs) const;
3455 // Set by resolve_any_subscript_array_type when it adopts an array type for
3456 // an Any-annotated `row = a[i]`-style assignment. The RHS in that case is a
3457 // raw index/slice expression rather than an already-materialized array
3458 // symbol, and the backend rejects a single whole-array-to-whole-array
3459 // code_assignt between those (Z3 sort mismatch) -- get_var_assign's final
3460 // store must copy it element by element instead.
3461 bool any_subscript_array_needs_copy_ = false;
3462 // An array-type probe may already have built this exprt while resolving the
3463 // RHS's real type. get_var_assign's RHS fetch reuses it instead of converting
3464 // the same RHS AST node a second time (which would duplicate any temporaries/
3465 // instructions the probe emitted, e.g. for fancy/mask/column selection).
3466 exprt cached_any_subscript_rhs_;
3467 bool has_cached_any_subscript_rhs_ = false;
3468 std::set<std::string> numpy_array_symbols_;
3469 std::unordered_map<irep_idt, std::string, irep_id_hash> class_object_names_;
3471 std::map<std::string, int> class_ids_;
3472
3475 bool unpack_record_trusted_ = false;
3476 std::unordered_map<std::string, std::string> numpy_view_copy_sources_;
3477 std::unordered_map<std::string, std::string> numpy_array_storage_aliases_;
3478 // A pointer-backed numpy view's logical shape (ADR-NP-003 etapa 2 scalar
3479 // strided views: 1-D unit-stride slices, 2-D row views, column views,
3480 // stepped/reversed 1-D slices, diagonal views, ravel/.flat). `length` is
3481 // the number of logical elements: __ESBMC_get_object_size on the pointer
3482 // reports the base object's remaining size from that offset, not this
3483 // (which may be shorter -- e.g. an empty view still points at a valid
3484 // position), so len() looks the value up here instead for a tracked view
3485 // symbol. `stride` is the step, in elements, between consecutive logical
3486 // indices (1 for unit-stride slices and row views, num_cols for column
3487 // views, num_cols+1 for the main diagonal, an explicit step for a
3488 // stepped slice). `readonly` rejects writing through the view (the
3489 // diagonal view NumPy itself treats as read-only); false for every other
3490 // kind. See list_access.cpp's handle_range_slice/handle_index_access and
3491 // converter_funcall.cpp's len() dispatch.
3492 struct numpy_scalar_pointer_view_infot
3493 {
3494 std::size_t length;
3495 long long stride;
3496 bool readonly;
3497 std::vector<std::size_t> shape;
3498 std::string source_id;
3499 // The other storages a view bound to different arrays on different
3500 // paths may point at.
3501 std::set<std::string> other_sources;
3502 // Per-axis element strides of an N-D view over a scalar pointer; empty
3503 // for a contiguous view (typed pointer to rows) or a legacy 1-D view.
3504 std::vector<long long> strides;
3505 // Runtime extents and strides, as the ids of the signed 64-bit temporaries
3506 // holding them ("" for an axis whose value is a constant). Parallel to
3507 // shape/strides, whose entries are placeholders for a runtime axis.
3508 std::vector<std::string> shape_symbols;
3509 std::vector<std::string> stride_symbols;
3510 bool is_symbolic() const
3511 {
3512 for (const std::string &id : shape_symbols)
3513 if (!id.empty())
3514 return true;
3515 for (const std::string &id : stride_symbols)
3516 if (!id.empty())
3517 return true;
3518 return false;
3519 }
3520 };
3521 std::unordered_map<std::string, numpy_scalar_pointer_view_infot>
3522 numpy_pointer_view_info_;
3525 std::map<std::string, numpy_nditer_state> numpy_nditers_;
3526 std::map<std::string, numpy_nditer_item> numpy_nditer_items_;
3527 nlohmann::json current_nditer_call_;
3528 std::string current_nditer_state_;
3529 unsigned nditer_counter_ = 0;
3530 std::vector<exprt> prebuilt_exprs_;
3531 const numpy_scalar_pointer_view_infot *
3532 find_numpy_pointer_view_info(const std::string &name) const;
3533 // Scans call sites of `func_name` for subscript view arguments at
3534 // `param_index`; returns the common elem type and view info when all sites
3535 // agree; returns false on conflict or when no analyzable view site exists.
3536 bool try_infer_numpy_view_param(
3537 const std::string &func_name,
3538 std::size_t param_index,
3539 typet &out_elem_type,
3540 numpy_scalar_pointer_view_infot &out_info) const;
3541 bool try_infer_numpy_view_param(
3542 const std::string &func_name,
3543 std::size_t param_index,
3544 typet &out_elem_type,
3545 numpy_scalar_pointer_view_infot &out_info,
3546 std::set<std::string> &visiting) const;
3547 std::optional<typet> numpy_literal_array_type(
3548 const std::string &arr_name,
3549 const std::string &function,
3550 int line,
3551 unsigned depth = 0) const;
3552 std::optional<typet> numpy_filled_array_type(
3553 const nlohmann::json &value,
3554 const std::string &function) const;
3555 std::optional<typet> numpy_arange_array_type(
3556 const nlohmann::json &value,
3557 const std::string &function) const;
3558 exprt list_argument_expr(const nlohmann::json &arg);
3561 typet returned_function_return_type(const nlohmann::json &call);
3562 typet stored_function_return_type(const nlohmann::json &value);
3565 std::optional<typet>
3566 dict_function_return_type(const nlohmann::json &container);
3567 bool dict_values(
3568 const nlohmann::json &container,
3569 std::vector<nlohmann::json> &out);
3570 typet subscript_call_return_type(
3571 const exprt &func_ptr,
3572 const nlohmann::json &func_node);
3573 std::optional<std::vector<std::size_t>>
3574 numpy_filled_array_shape(const nlohmann::json &value) const;
3575 const std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>> &
3576 inferred_numpy_view_param(
3577 const std::string &func_name,
3578 std::size_t param_index);
3579 bool is_bound_numpy_view_param(
3580 const std::string &func_name,
3581 std::size_t param_index);
3582 void reject_numpy_view_argument_type_mismatch(const nlohmann::json &call);
3583 std::map<
3584 std::string,
3585 std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>>>
3586 numpy_view_param_layouts_;
3587 // Parameters whose conversion has decided whether they bind a view, and
3588 // what callers converted before that were told.
3589 std::set<std::string> numpy_view_params_decided_;
3590 std::map<std::string, bool> numpy_view_params_assumed_;
3591 static std::optional<numpy_scalar_pointer_view_infot>
3592 slice_view_info(std::size_t length, const nlohmann::json &slice_node);
3593 static std::optional<numpy_scalar_pointer_view_infot> row_slice_view_info(
3594 std::size_t rows,
3595 std::size_t cols,
3596 const nlohmann::json &slice_node);
3597 static std::optional<numpy_scalar_pointer_view_infot> column_view_info(
3598 std::size_t rows,
3599 std::size_t cols,
3600 const nlohmann::json &slice_node);
3601 static std::optional<numpy_scalar_pointer_view_infot>
3602 view_info_from_subscript(
3603 const std::vector<std::size_t> &src_shape,
3604 const nlohmann::json &slice_node);
3605 static numpy_scalar_pointer_view_infot
3606 runtime_view_info(std::size_t rank = 1);
3607 static std::optional<numpy_scalar_pointer_view_infot>
3608 slice_or_runtime_view_info(
3609 std::size_t length,
3610 const nlohmann::json &slice_node);
3611 static std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>>
3612 merge_view_layouts(
3613 const std::pair<typet, numpy_scalar_pointer_view_infot> &a,
3614 const std::pair<typet, numpy_scalar_pointer_view_infot> &b);
3615 // Symbol ids holding the extent and stride of each axis of a view whose
3616 // layout is read at run time.
3617 struct numpy_runtime_view_layoutt
3618 {
3619 std::vector<std::string> extents;
3620 std::vector<std::string> strides;
3621 };
3622 // Keyed like numpy_view_params_: the statics every caller writes, and the
3623 // parameter symbol with the callee's own copies.
3624 std::map<std::string, numpy_runtime_view_layoutt> numpy_runtime_view_statics_;
3625 std::map<std::string, std::pair<std::string, numpy_runtime_view_layoutt>>
3626 numpy_runtime_view_locals_;
3627 const nlohmann::json *numpy_runtime_bound_call_ = nullptr;
3628 const numpy_runtime_view_layoutt &
3629 runtime_numpy_view_statics(const std::string &key, std::size_t rank);
3630 void declare_runtime_numpy_view_param(
3631 numpy_scalar_pointer_view_infot &info,
3632 const std::string &arg_id,
3633 const std::string &key);
3634 void prepend_runtime_numpy_view_prologue(
3635 const std::string &function_id,
3636 exprt &function_body);
3637 void bind_runtime_numpy_view_arguments(
3638 const nlohmann::json &statement,
3639 codet &target_block);
3640 void store_runtime_numpy_view_layout(
3641 const nlohmann::json &call,
3642 const std::string &func_name,
3643 std::size_t param_index,
3644 codet &target_block);
3645 std::string numpy_view_callee_of(const nlohmann::json &call);
3646 std::vector<std::size_t>
3647 runtime_numpy_view_params(const std::string &func_name);
3648 void reject_unbound_runtime_numpy_view_call(const nlohmann::json &call);
3649 static bool same_view_layout(
3650 const std::pair<typet, numpy_scalar_pointer_view_infot> &a,
3651 const std::pair<typet, numpy_scalar_pointer_view_infot> &b);
3652 static std::optional<numpy_scalar_pointer_view_infot> subview_info(
3653 const numpy_scalar_pointer_view_infot &parent,
3654 const nlohmann::json &slice_node);
3655 std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>>
3656 infer_diagonal_view_layout(
3657 const nlohmann::json &call,
3658 const std::string &function) const;
3659 std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>>
3660 infer_branch_bound_view_layout(
3661 const nlohmann::json &node,
3662 const std::string &function,
3663 std::set<std::string> &visiting,
3664 unsigned depth) const;
3665 std::optional<std::pair<typet, numpy_scalar_pointer_view_infot>>
3666 infer_numpy_view_layout(
3667 const nlohmann::json &node,
3668 const std::string &function,
3669 std::set<std::string> &visiting,
3670 unsigned depth = 0) const;
3671 std::optional<numpy_scalar_pointer_view_infot> infer_numpy_view_param_type(
3672 const std::string &func_name,
3673 std::size_t param_index,
3674 const std::string &arg_name,
3675 bool numpy_array_param,
3676 typet &arg_type) const;
3677 void register_numpy_view_param(
3678 const std::optional<numpy_scalar_pointer_view_infot> &view_param,
3679 const std::string &arg_id,
3680 const std::string &func_name,
3681 std::size_t param_index);
3682 // Runtime length of the named view when its extent is not a constant.
3683 std::optional<exprt>
3684 symbolic_numpy_view_length(const std::string &name) const;
3685 // Axis `axis` extent / stride of a view as signed 64-bit expressions.
3686 exprt numpy_view_extent(
3687 const numpy_scalar_pointer_view_infot &info,
3688 std::size_t axis) const;
3689 exprt numpy_view_stride(
3690 const numpy_scalar_pointer_view_infot &info,
3691 std::size_t axis) const;
3692 // Consumers that need a constant length/stride reject a symbolic view.
3693 static void
3694 reject_symbolic_numpy_view(const numpy_scalar_pointer_view_infot &info);
3695
3697 struct strided_copy_axis
3698 {
3699 exprt extent;
3700 exprt stride;
3701 };
3702
3706 void emit_strided_copy(
3707 codet &block,
3708 const exprt &dst,
3709 const exprt &src,
3710 const exprt &offset,
3711 const std::vector<strided_copy_axis> &axes,
3712 const locationt &location);
3713
3717 std::string snapshot_symbolic_numpy_view(
3718 const exprt &old_ptr,
3719 numpy_scalar_pointer_view_infot &info,
3720 const locationt &location,
3721 codet &target_block);
3722 void reject_numpy_view_rebind() const;
3727 bool accepts_numpy_view_binding(
3728 const std::string &lhs_id,
3729 const numpy_scalar_pointer_view_infot &candidate,
3730 const typet &view_ptr_type,
3731 const exprt &source);
3732 bool can_merge_numpy_view_layouts(const std::string &view_id) const;
3733 const numpy_runtime_view_layoutt &
3734 numpy_view_layout_vars(const std::string &view_id, std::size_t rank);
3735 void record_numpy_view_layout(
3736 const std::string &view_id,
3737 const std::string &storage_id);
3738 void merge_numpy_view_binding(const std::string &view_id, bool same_kind);
3739 static bool same_numpy_view_kind(
3740 const numpy_scalar_pointer_view_infot &a,
3741 const numpy_scalar_pointer_view_infot &b);
3742 // Layout variables of each view name, the function-local ones among them,
3743 // and the names whose metadata reads them.
3744 std::map<std::string, numpy_runtime_view_layoutt> numpy_view_layout_vars_;
3745 std::vector<std::string> numpy_view_layout_locals_;
3746 std::set<std::string> numpy_merged_views_;
3747 std::map<std::string, std::set<std::string>> numpy_view_other_sources_;
3748 std::set<std::string> numpy_view_storage_roots(const std::string &id) const;
3749 unsigned numpy_loop_depth_ = 0;
3750 // Conditional expressions being converted; their arms run on one path only.
3751 unsigned conditional_expr_depth_ = 0;
3752 // Converting an and/or operand into the block of effects it owns.
3753 bool in_operand_effects_block_ = false;
3756 std::vector<exprt> read_strided_view_elements(
3757 const exprt &base,
3758 const std::vector<long long> &strides,
3759 const std::vector<std::size_t> &shape);
3760 std::vector<exprt> read_contiguous_view_elements(
3761 exprt base,
3762 std::size_t count,
3763 long long stride,
3764 const std::vector<std::size_t> &shape);
3765 std::string snapshot_constant_numpy_view(
3766 const symbolt &view_symbol,
3767 numpy_scalar_pointer_view_infot &info,
3768 const locationt &location,
3769 codet &target_block);
3773 struct numpy_view_containert
3774 {
3775 std::vector<std::string> elements;
3776 std::map<std::string, std::size_t> keys;
3777 bool is_dict = false;
3778 };
3779 std::unordered_map<std::string, numpy_view_containert> numpy_view_containers_;
3780 std::size_t numpy_view_container_count_ = 0;
3781 const numpy_view_containert *
3782 find_numpy_view_container(const nlohmann::json &node) const;
3783 std::string numpy_view_container_element(
3784 const numpy_view_containert &container,
3785 const nlohmann::json &slice) const;
3786 std::optional<nlohmann::json>
3787 resolve_numpy_view_container_use(const nlohmann::json &node) const;
3790 nlohmann::json
3791 rewrite_numpy_view_container_reads(const nlohmann::json &node) const;
3792 const nlohmann::json &resolve_numpy_view_containers(
3793 const nlohmann::json &statement,
3794 nlohmann::json &rewritten) const;
3795 bool try_bind_numpy_view_container(
3796 const nlohmann::json &ast_node,
3797 codet &target_block);
3800 std::unordered_set<std::string> numpy_view_return_functions_;
3803 std::unordered_set<std::string> numpy_fold_only_functions_;
3805 std::unordered_set<std::string> numpy_escaped_storage_;
3807 std::unordered_set<std::string> numpy_readonly_arrays_;
3809 std::vector<std::string> model_namespaces_;
3810 // A 2-D+ numpy array parameter's full logical shape, keyed by the
3811 // parameter's own symbol id. register_function_argument decays such a
3812 // parameter to a pointer to its row type for the C ABI (gen_pointer_type
3813 // over arg_type.subtype()), which is what the backend needs but erases the
3814 // outer dimension from the parameter's own type -- unwrapping the pointer
3815 // recovers only the row shape, not the row count. `.shape`/`.ndim`/`.size`
3816 // and the array-consuming numpy calls (transpose, sort/argsort/
3817 // searchsorted, reducers) read the pre-decay shape from here instead.
3818 std::unordered_map<std::string, std::vector<std::size_t>> numpy_param_shapes_;
3819 std::unordered_map<std::string, typet> numpy_param_array_types_;
3820 std::unordered_set<std::string> numpy_ambiguous_shape_symbols_;
3821 // List parameters mixing strings and numbers whose call sites agree on
3822 // each position's type, so a constant index reads that type (#8670).
3823 std::unordered_set<std::string> positional_list_params_;
3824 // Keys are "func_name#param_index" for parameters that receive numpy views
3825 // and have registered view metadata in numpy_pointer_view_info_.
3826 std::set<std::string> numpy_view_params_;
3828 std::unordered_set<std::string> numpy_view_param_symbols_;
3829 bool is_loading_models = false;
3830 bool is_importing_module = false;
3831 bool base_ctor_called = false;
3832 bool build_static_lists = false;
3835 typet numpy_element_type;
3836
3844 std::set<std::string> call_escaped_lists_;
3845
3847 std::map<std::string, std::set<std::string>> instance_attr_map;
3850 std::map<std::string, std::set<std::string>> certain_instance_attrs_;
3852 std::unordered_map<std::string, std::string> imported_modules;
3853
3860 std::map<std::string, nlohmann::json> module_ast_pool_;
3864 std::unordered_map<std::string, std::string> input_str_to_len_sym_;
3865
3873 std::unordered_map<std::string, std::string> retype_aliases_;
3876 symbolt *follow_retype_alias(symbolt *symbol) const;
3878 symbolt *retype_store_symbol(
3879 const nlohmann::json &target,
3880 const exprt &lhs,
3881 symbolt *lhs_symbol);
3882
3885 std::unordered_map<std::string, std::pair<std::string, typet>>
3886 unbound_global_flags_;
3890 std::unordered_map<std::string, std::string> unmodelled_base_classes_;
3892 std::unordered_set<std::string> str_valued_symbols_;
3894 std::unordered_set<std::string> str_assigned_symbols_;
3896 std::unordered_set<std::string> out_of_scope_locals_;
3899 void end_block_scope(const code_blockt &block);
3900
3909 std::unordered_map<std::string, std::string> flow_class_map_;
3910
3913 std::string flow_lvalue_path(const nlohmann::json &node) const;
3914
3917 std::string flow_rhs_class(const nlohmann::json &rhs) const;
3918
3923 std::string alias_rhs_class(const nlohmann::json &rhs);
3924
3933 std::string call_return_class(const nlohmann::json &rhs) const;
3934
3938 unsigned block_nesting_ = 0;
3939
3950 unsigned function_body_depth_ = 0;
3951
3958 unsigned loop_body_depth_ = 0;
3959
3960 function_call_cache function_call_cache_;
3961
3962 std::vector<std::string> global_declarations;
3965 std::map<std::string, std::string> nonlocal_scopes_;
3966 std::vector<std::string> local_loads;
3967 bool is_right = false;
3968 std::vector<std::string> scope_stack_;
3969
3970 exprt extract_type_from_boolean_op(const exprt &bool_op);
3971};
void base_type(type2tc &type, const namespacet &ns)
Definition base_type.cpp:6
static const twodig_t base
Definition bigint.cpp:28
#define new_ast
Definition bitwuzla_conv.cpp:5
static void convert_expression_to_code(exprt &expr)
Definition clang_c_adjust_polymorphic_functions.cpp:492
Definition std_code.h:49
Definition std_types.h:280
Definition std_code.h:8
Definition context.h:57
The single owner of per-instance element-type tracking for the Python frontend: "which types does thi...
Definition element_type_registry.h:49
Definition expr.h:34
bool is_constant() const
Definition expr.cpp:105
Dedicated cache for function-call resolution data.
Definition cache.h:12
Definition expr.h:26
Definition converter_expr.cpp:202
Definition global_scope.h:7
Definition irep_idt.h:12
bool empty() const
Definition irep_idt.h:54
bool is_array() const
Definition irep.h:1125
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:127
typet & type()
Definition irep.h:153
Definition location.h:7
Definition module_locator.h:8
Definition module.h:60
Definition namespace.h:10
Definition python_class_builder.h:14
void update_symbol(const exprt &expr) const
Definition converter_symbols.cpp:15
friend class numpy_nditer
Definition python_converter.h:669
bool safe_to_emit_side_effecting_statement() const
Definition python_converter.h:373
exprt create_lhs_expression(const nlohmann::json &target, symbolt *lhs_symbol, const locationt &location)
Definition converter_stmt.cpp:1098
function_call_cache & get_function_call_cache()
Definition python_converter.h:311
void restore_contract_clause(bool saved)
Definition python_converter.h:633
string_builder & get_string_builder()
Definition python_converter.cpp:113
exprt class_mro_tuple(const nlohmann::json &element)
Cls.__mro__ as a tuple of class objects.
Definition converter_expr.cpp:310
bool can_emit_catchable_guard() const
Definition python_converter.h:391
const python_exception_handler & get_exception_handler() const
Definition python_converter.h:208
friend class python_converter_test_access
Definition python_converter.h:682
tuple_handler & get_tuple_handler() const
Definition python_converter.h:228
void set_converting_rhs(bool value)
Definition python_converter.h:89
friend class python_exception_handler
Definition python_converter.h:680
exprt compare_class_values(const std::string &op, const exprt &lhs, const exprt &rhs)
is, is not, == or != with a runtime class value on a side; nil when neither side is one.
Definition converter_compare.cpp:1232
friend class function_call_expr
Definition python_converter.h:666
typet get_callable_type(const nlohmann::json &annotation, const nlohmann::json &stmt)
Callable[[A, B], R] as the function-pointer type R (*)(A, B); the generic Callable pointer when the s...
Definition converter_types.cpp:215
exprt as_class_value(const exprt &e)
e as a runtime class value when it is one, a class object, or a conditional between such; nil otherwi...
Definition converter_compare.cpp:1217
exprt get_expr(const nlohmann::json &element)
Definition converter_expr.cpp:2402
friend class tuple_handler
Definition python_converter.h:674
symbolt create_symbol(const std::string &module, const std::string &name, const std::string &id, const locationt &location, const typet &type) const
Definition converter_util.cpp:22
const std::string & main_python_filename() const
Definition python_converter.h:287
bool is_imported_module(const std::string &module_name) const
Definition converter_symbols.cpp:1352
exprt not_callable_function(const typet &function, const typet &value, const locationt &location)
A function with function's type whose only effect is to raise the TypeError CPython raises on calling...
Definition converter_stmt.cpp:5331
const nlohmann::json & get_ast_json() const
Definition python_converter.h:119
const std::string & current_function_name() const
Definition python_converter.h:292
exprt fit_numpy_integer_store(const exprt &lhs, const exprt &rhs, const nlohmann::json &value)
Definition converter_stmt.cpp:7133
bool binds_runtime_class(const nlohmann::json &ast_node, const exprt &rhs)
Whether assigning rhs to the variable ast_node targets makes that variable a runtime class value: a c...
Definition converter_stmt.cpp:1649
typet returned_function_type(const nlohmann::json &function_node)
A bare Callable return as the pointer type of the functions the body returns by name,...
Definition converter_funcdef.cpp:4089
void add_symbol(const symbolt s)
Definition python_converter.h:321
friend class complex_handler
Definition python_converter.h:665
bool call_lambda_copy(const nlohmann::json &element, const symbolt &var, side_effect_expr_function_callt &call, const code_typet *&callee_type)
Retarget call to that copy, if there is one.
Definition converter_funcall.cpp:874
friend class type_handler
Definition python_converter.h:671
friend class string_handler
Definition python_converter.h:673
void capture_lambda_free_variables(const nlohmann::json &lambda_node, const std::string &lambda_id, const locationt &location)
Bind a static cell, named under lambda_id, for each scalar free variable of lambda_node that is a loc...
Definition converter_funcdef.cpp:324
exprt guard_none_conversion(exprt operand, const std::string &message, const nlohmann::json &element)
Definition converter_binop.cpp:706
std::string get_op(const std::string &op, const typet &type) const
Definition python_converter.cpp:58
python_math & get_math_handler()
Definition python_converter.h:213
python_converter(contextt &_context, const nlohmann::json *ast, const global_scope &gs, const std::vector< nlohmann::json > *extra_asts=nullptr)
Definition python_converter.cpp:63
bool is_module_receiver(const std::string &module_name, const nlohmann::json &receiver, const nlohmann::json &use) const
Whether receiver of the call at use is the imported module module_name rather than a binding that sha...
Definition converter_symbols.cpp:599
symbolt * add_symbol_and_get_ptr(symbolt &symbol)
Definition python_converter.h:105
string_handler & get_string_handler()
Definition python_converter.h:223
std::optional< code_typet > returned_function(const nlohmann::json &callee)
The function a call of callee returns, when its type is known before converting it: get() or get()() ...
Definition converter_funcall.cpp:701
friend class bounded_math
Definition python_converter.h:664
const std::string & current_classname() const
Definition python_converter.h:297
friend class function_call_builder
Definition python_converter.h:670
friend class numpy_random
Definition python_converter.h:668
bool may_be_callable(const typet &type)
Unknown, function or class-instance types: a call on such a value may succeed.
Definition converter_funcall.cpp:637
typet named_callee_type(const std::string &name)
The type of the function a call of the name name runs: the function a variable holds,...
Definition converter_funcall.cpp:683
std::optional< exprt > call_property_value(const nlohmann::json &element)
Definition converter_funcall.cpp:595
void copy_location_fields_from_decl(const nlohmann::json &from, nlohmann::json &to) const
Definition converter_util.cpp:88
void mark_list_call_escaped(const std::string &id)
Record that a list symbol escaped into a function/method call and may have been mutated by the callee...
Definition python_converter.h:260
const std::string get_imported_module_path(const std::string &module_name) const
Definition python_converter.h:521
bool enter_contract_clause(bool entering)
Enters a contract clause or loop invariant, staying entered when already inside one.
Definition python_converter.h:629
friend class get_expr_depth_guard
Definition python_converter.h:681
bool is_retyped(const irep_idt &id) const
Whether a straight-line retype moved id's value to another symbol.
Definition python_converter.h:476
nlohmann::json callable_function_stubs() const
FunctionDef stubs, each only a name and its returns, for the functions a call in the current module c...
Definition python_converter.cpp:288
std::string current_ast_scope() const
The current function as the AST lookups in json_utils name it: a method is "Cls@C@m",...
Definition converter_symbols.cpp:1375
exprt concat_tuple_with_list(const exprt &lhs, const exprt &rhs, const nlohmann::json &element)
Definition converter_binop.cpp:3728
static std::optional< bool > binding_is_import(const nlohmann::json &module, const scope_bindings &global, const nlohmann::json *function, bool in_class, bool in_order, const std::string &name, const nlohmann::json &use)
Whether name, read at use inside function (null at module or class level), reads a binding made by an...
Definition converter_symbols.cpp:535
size_t current_block_statement_count() const
Definition python_converter.h:641
void convert_lambda_call(const nlohmann::json &element, side_effect_expr_function_callt &call)
Definition converter_funcall.cpp:762
friend class python_typechecking
Definition python_converter.h:676
exprt get_literal(const nlohmann::json &element)
Definition converter_expr.cpp:375
python_dict_handler * get_dict_handler()
Definition python_converter.h:198
bool type_assertions_enabled() const
Definition converter_util.cpp:107
size_t unordered_tuple_component(exprt &lhs, exprt &rhs, const nlohmann::json &element)
The index of the first component pair, within the common prefix of two tuples, that is neither two nu...
Definition converter_binop.cpp:3602
exprt make_class_object(const std::string &name)
A class used as a value (x = int, type(v)): its name as a char array, also held in value for the fold...
Definition converter_expr.cpp:285
friend class python_list
Definition python_converter.h:672
friend class python_class_builder
Definition python_converter.h:677
symbolt * find_symbol(const std::string &symbol_id) const
Definition converter_symbols.cpp:1272
bool name_shadows_module(const nlohmann::json &receiver, const nlohmann::json &use) const
Whether receiver, a Name read by the call at use, is bound in its scope by something other than an im...
Definition converter_symbols.cpp:568
void outlive_scope(const std::string &id)
Makes id, a local of a nested body that has been closed, outlive that body, so that a later read does...
Definition converter_stmt.cpp:10166
const function_call_cache & get_function_call_cache() const
Definition python_converter.h:316
void add_instruction(const exprt &expr)
Definition python_converter.h:326
exprt guard_nonfinite_float_to_int(exprt operand, const nlohmann::json &element, bool reject_none=false)
Definition converter_binop.cpp:666
void set_current_element_type(const typet &type)
Definition python_converter.h:101
typet get_type_from_annotation(const nlohmann::json &annotation_node, const nlohmann::json &element)
Definition converter_types.cpp:442
bool settle_target_type(symbolt *lhs_symbol, exprt &lhs, exprt &rhs, const nlohmann::json &ast_node)
Whether the assignment's target type is settled without the usual adjustments: a subscript keeps its ...
Definition converter_stmt.cpp:1568
exprt handle_string_comparison(const std::string &op, exprt &lhs, exprt &rhs, const nlohmann::json &element)
Definition converter_compare.cpp:335
void guard_attribute_on_none(const exprt &base, const std::string &attr_name, const nlohmann::json &element, bool is_self=false)
Before an access to base.attr_name through a class pointer that may be None, raises AttributeError wh...
Definition converter_binop.cpp:596
typet get_optional_type(const nlohmann::json &slice)
The type of Optional[<slice>], or an empty typet when the slice is not handled.
Definition converter_types.cpp:404
python_exception_handler & get_exception_handler()
Definition python_converter.h:203
const symbolt * lambda_copy_for_call(const nlohmann::json &call, const symbolt &var)
The copy of the once-bound lambda var points to, converted for a call passing an int where its one si...
Definition converter_funcall.cpp:834
std::string current_module_name() const
Stem of the file being converted, i.e.
Definition converter_symbols.cpp:1370
locationt get_location_from_decl(const nlohmann::json &element) const
Definition converter_util.cpp:74
void set_current_func_name(const std::string &name)
Definition python_converter.h:97
bool emit_statement_into_current_block(const nlohmann::json &ast_node)
Definition python_converter.h:338
contextt & symbol_table() const
Definition python_converter.h:238
type_handler & get_type_handler()
Definition python_converter.h:243
const nlohmann::json & ast() const
Definition python_converter.h:233
codet get_compound_store(const exprt &lhs, const exprt &rhs, const locationt &location)
Definition converter_stmt.cpp:8623
typet named_return_type(const std::string &name, const nlohmann::json &return_node, const nlohmann::json &function_node)
Definition converter_funcdef.cpp:4109
exprt class_value(const std::string &name)
The runtime class value (#8390) of the class name.
Definition converter_compare.cpp:1207
bool scalar_order(exprt a, exprt b, const nlohmann::json &element, expr2tc &lt, expr2tc &eq)
The strict order and equality of two tuple components that are numbers (a mixed int/float pair compar...
Definition converter_binop.cpp:3546
~python_converter()
Definition python_converter.cpp:93
void emit_guarded_raise(const exprt &cond, const std::string &exception, const std::string &message, const locationt &location)
Definition converter_binop.cpp:617
friend class python_set
Definition python_converter.h:679
static bool is_class_object(const exprt &expr)
Definition python_converter.h:584
const element_type_registry & get_element_type_registry() const
Definition python_converter.h:253
exprt make_char_array_expr(const std::vector< unsigned char > &string_literal, const typet &t)
Definition converter_expr.cpp:265
bool in_contract_clause() const
Definition python_converter.h:637
void set_current_lhs(exprt *value)
Definition python_converter.h:93
void convert()
Definition python_converter.cpp:871
void ensure_void_void_intrinsic(const std::string &name, const locationt &location)
Definition converter_util.cpp:48
bool is_list_call_escaped(const std::string &id) const
Definition python_converter.h:265
const namespacet & name_space() const
Definition python_converter.h:306
exprt handle_tuple_operations(const std::string &op, exprt &lhs, exprt &rhs, const nlohmann::json &element)
Handles tuple +/* operators and lexicographic ordering.
Definition converter_binop.cpp:3781
typet optional_container_type(const nlohmann::json &slice)
Optional[C[...]] for a subscripted container C: a list or set is already a pointer,...
Definition converter_types.cpp:387
static scope_bindings module_scope_bindings(const nlohmann::json &module, const std::string &name)
The bindings of name in module's own scope, with declared_outer meaning that a function rebinds it th...
Definition converter_symbols.cpp:558
ExpressionType expression_type(const nlohmann::json &element) const
The category get_expr converts element as; CLASS_MRO for Cls.__mro__ on a class whose MRO is known.
Definition converter_expr.cpp:296
exprt handle_tuple_add(const exprt &lhs, const exprt &rhs, const nlohmann::json &element)
a + b where an operand is a tuple struct.
Definition converter_binop.cpp:3668
void raise_on_unordered_tie(const std::string &op, const exprt &lhs, const exprt &rhs, size_t unordered, const expr2tc &prefix_eq, const nlohmann::json &element)
Raise CPython's TypeError when two tuples tie on every component before the pair at unordered,...
Definition converter_binop.cpp:3637
const std::string & python_file() const
Definition python_converter.h:282
const std::string & get_current_func_name() const
Definition python_converter.h:115
friend class python_dict_handler
Definition python_converter.h:678
void defer_check(std::function< void()> check)
Runs check once every statement has been converted.
Definition python_converter.h:275
exprt hoist_side_effecting_operand(const exprt &operand, const nlohmann::json &element, const std::string &prefix)
Definition converter_binop.cpp:577
friend class dynamic_type_handler
Definition python_converter.h:675
std::optional< exprt > call_returned_function(const nlohmann::json &element)
get()(): a call through the function pointer that get() returns.
Definition converter_funcall.cpp:890
element_type_registry & get_element_type_registry()
Definition python_converter.h:248
const std::string * class_object_name(const irep_idt &id) const
The class a variable was last assigned as a value (x = int), or null.
Definition python_converter.h:649
bool can_emit_runtime_guard() const
Definition python_converter.h:382
void decay_function_choice(exprt &then, exprt &else_expr)
A choice between two functions of one type is a pointer to either.
Definition converter_stmt.cpp:5356
complex_handler & get_complex_handler()
Definition python_converter.h:218
python_typechecking & get_typechecker()
Definition python_converter.cpp:103
friend class numpy_call_expr
Definition python_converter.h:667
symbolt * contract_return_value_symbol(const std::string &var_name, const nlohmann::json &element)
Symbol for __ESBMC_return_value in an ensures clause, null when the name is something else or the fun...
Definition converter_expr.cpp:582
Handles Python exception-related statement conversion.
Definition python_exception_handler.h:24
Definition python_lambda.h:14
Handles mathematical operations for Python-to-C conversion.
Definition python_math.h:27
Definition python_typechecking.h:20
Definition std_code.h:905
Helper class for building and manipulating string expressions in Python frontend Handles null-termina...
Definition string_builder.h:20
Definition std_types.h:232
Definition symbol_id.h:6
Definition symbol.h:12
Handler for Python tuple operations.
Definition tuple_handler.h:20
Definition type_handler.h:113
static bool is_optional_struct(const typet &t)
Definition type_utils.h:257
Definition type.h:9
Definition toml.hpp:1531
@ function
Definition converter_compare.cpp:885
pthread_cond_t cond
Definition cuda.h:50
int count
Definition cuda.h:51
irep_container< expr2t > expr2tc
Definition irep2.h:431
list[float] empty(int shape)
Definition numpy.py:29
static std::optional< std::string > string_literal(const nlohmann::json &node)
Definition expr.cpp:7235
bool is_imported_numpy_module_alias(const nlohmann::json &ast, const std::string &name)
Definition converter_stmt.cpp:756
Handler for Python dictionary operations in ESBMC's Python frontend.
void * value
Definition solidity_mapping.c:2
uint256_t key
Definition solidity_mapping.c:1
unsigned stack_budget_guardt< Tag >::depth
Definition stack_budget.h:72
Definition module.h:12
Definition python_converter.h:61
const nlohmann::json * call
Definition python_converter.h:62
std::string enclosing_function
Definition python_converter.h:63
How one scope binds a name: by an import, by anything else, or by a global/nonlocal declaration handi...
Definition python_converter.h:483
bool by_import
Definition python_converter.h:484
bool declared_outer
Definition python_converter.h:486
bool by_other
Definition python_converter.h:485
ExpressionType
Definition type_utils.h:43