1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use libc::{c_schar, c_int};
#[cfg(not(Py_3_11))]
use libc::c_char;

use crate::code::{PyCodeObject};
#[cfg(not(Py_3_11))]
use crate::code::CO_MAXBLOCKS;
use crate::object::*;
use crate::pystate::PyThreadState;

#[cfg(not(Py_LIMITED_API))]
pub type PyFrameState = c_schar;

#[cfg(not(Py_LIMITED_API))]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyTryBlock {
    pub b_type: c_int,
    pub b_handler: c_int,
    pub b_level: c_int,
}

/// In Python > 3.11, frame object internals are always private
///
/// This improves performance by creating frame object lazily.
/// There are now getter methods to get info from the frame.
#[cfg(any(Py_LIMITED_API, Py_3_11))]
#[repr(C)]
pub struct PyFrameObject {
    _private: [u8; 0],
}

#[cfg(all(not(Py_LIMITED_API), not(Py_3_11)))]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyFrameObject {
    pub ob_base: PyVarObject,
    pub f_back: *mut PyFrameObject,       /* previous frame, or NULL */
    pub f_code: *mut PyCodeObject,        /* code segment */
    pub f_builtins: *mut PyObject,        /* builtin symbol table (PyDictObject) */
    pub f_globals: *mut PyObject,         /* global symbol table (PyDictObject) */
    pub f_locals: *mut PyObject,          /* local symbol table (any mapping) */
    pub f_valuestack: *mut *mut PyObject, /* points after the last local */
    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
    Frame evaluation usually NULLs it, but a frame that yields sets it
    to the current stack top. */
    #[cfg(not(Py_3_10))]
    pub f_stacktop: *mut *mut PyObject,
    pub f_trace: *mut PyObject, /* Trace function */
    #[cfg(Py_3_10)]
    pub f_stackdepth: c_int,

    #[cfg(not(Py_3_7))]
    pub f_exc_type: *mut PyObject,
    #[cfg(not(Py_3_7))]
    pub f_exc_value: *mut PyObject,
    #[cfg(not(Py_3_7))]
    pub f_exc_traceback: *mut PyObject,

    #[cfg(Py_3_7)]
    pub f_trace_lines: c_char,
    #[cfg(Py_3_7)]
    pub f_trace_opcodes: c_char,

    #[cfg(not(Py_3_4))]
    pub f_tstate: *mut PyThreadState,

    #[cfg(Py_3_4)]
    pub f_gen: *mut PyObject,

    pub f_lasti: c_int, /* Last instruction if called */
    /* Call PyFrame_GetLineNumber() instead of reading this field
     directly.  As of 2.3 f_lineno is only valid when tracing is
     active (i.e. when f_trace is set).  At other times we use
     PyCode_Addr2Line to calculate the line from the current
    bytecode index. */
    pub f_lineno: c_int, /* Current line number. Only valid if non-zero */
    pub f_iblock: c_int, /* index in f_blockstack */
    #[cfg(all(Py_3_4, not(Py_3_10)))]
    pub f_executing: c_char, /* whether the frame is still executing */
    #[cfg(Py_3_10)]
    pub f_state: PyFrameState,  /* What state the frame is in */
    pub f_blockstack: [PyTryBlock; CO_MAXBLOCKS], /* for try and loop blocks */
    pub f_localsplus: [*mut PyObject; 1], /* locals+stack, dynamically sized */
}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    pub static mut PyFrame_Type: PyTypeObject;
}

#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn PyFrame_Check(op: *mut PyObject) -> c_int {
    (Py_TYPE(op) == &mut PyFrame_Type) as c_int
}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    pub fn PyFrame_New(
        tstate: *mut PyThreadState,
        code: *mut PyCodeObject,
        globals: *mut PyObject,
        locals: *mut PyObject,
    ) -> *mut PyFrameObject;

    #[cfg(not(Py_3_11))]
    pub fn PyFrame_BlockSetup(
        f: *mut PyFrameObject,
        _type: c_int,
        handler: c_int,
        level: c_int,
    ) -> ();
    #[cfg(not(Py_3_11))]
    pub fn PyFrame_BlockPop(f: *mut PyFrameObject) -> *mut PyTryBlock;

    pub fn PyFrame_LocalsToFast(f: *mut PyFrameObject, clear: c_int) -> ();
    #[cfg(Py_3_4)]
    pub fn PyFrame_FastToLocalsWithError(f: *mut PyFrameObject) -> c_int;
    pub fn PyFrame_FastToLocals(f: *mut PyFrameObject) -> ();

    #[cfg(not(Py_3_9))]
    pub fn PyFrame_ClearFreeList() -> c_int;

    #[cfg(Py_3_9)]
    pub fn PyFrame_GetBack(frame: *mut PyFrameObject) -> *mut PyFrameObject;

    #[cfg(Py_3_11)]
    pub fn PyFrame_GetBuiltins(frame: *mut PyFrameObject) -> *mut PyObject;

    #[cfg(Py_3_11)]
    pub fn PyFrame_GetGenerator(frame: *mut PyFrameObject) -> *mut PyObject;


    #[cfg(Py_3_11)]
    pub fn PyFrame_GetGlobals(frame: *mut PyFrameObject) -> *mut PyObject;

   #[cfg(Py_3_11)]
    pub fn PyFrame_GetLasti(frame: *mut PyFrameObject) -> c_int;

   #[cfg(Py_3_11)]
    pub fn PyFrame_GetLocals(frame: *mut PyFrameObject) -> *mut PyObject;
}   

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    pub fn PyFrame_GetLineNumber(f: *mut PyFrameObject) -> c_int;

    #[cfg(Py_3_9)]
    pub fn PyFrame_GetCode(frame: *mut PyFrameObject) -> *mut PyCodeObject;
}