rustpython_compiler_core/
bytecode.rs

1//! Implement python as a virtual machine with bytecode. This module
2//! implements bytecode structure.
3
4use bitflags::bitflags;
5use itertools::Itertools;
6use malachite_bigint::BigInt;
7use num_complex::Complex64;
8use rustpython_parser_core::source_code::{OneIndexed, SourceLocation};
9use std::marker::PhantomData;
10use std::{collections::BTreeSet, fmt, hash, mem};
11
12pub use rustpython_parser_core::ConversionFlag;
13
14pub trait Constant: Sized {
15    type Name: AsRef<str>;
16
17    /// Transforms the given Constant to a BorrowedConstant
18    fn borrow_constant(&self) -> BorrowedConstant<Self>;
19}
20
21impl Constant for ConstantData {
22    type Name = String;
23    fn borrow_constant(&self) -> BorrowedConstant<Self> {
24        use BorrowedConstant::*;
25        match self {
26            ConstantData::Integer { value } => Integer { value },
27            ConstantData::Float { value } => Float { value: *value },
28            ConstantData::Complex { value } => Complex { value: *value },
29            ConstantData::Boolean { value } => Boolean { value: *value },
30            ConstantData::Str { value } => Str { value },
31            ConstantData::Bytes { value } => Bytes { value },
32            ConstantData::Code { code } => Code { code },
33            ConstantData::Tuple { elements } => Tuple { elements },
34            ConstantData::None => None,
35            ConstantData::Ellipsis => Ellipsis,
36        }
37    }
38}
39
40/// A Constant Bag
41pub trait ConstantBag: Sized + Copy {
42    type Constant: Constant;
43    fn make_constant<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant;
44    fn make_int(&self, value: BigInt) -> Self::Constant;
45    fn make_tuple(&self, elements: impl Iterator<Item = Self::Constant>) -> Self::Constant;
46    fn make_code(&self, code: CodeObject<Self::Constant>) -> Self::Constant;
47    fn make_name(&self, name: &str) -> <Self::Constant as Constant>::Name;
48}
49
50pub trait AsBag {
51    type Bag: ConstantBag;
52    #[allow(clippy::wrong_self_convention)]
53    fn as_bag(self) -> Self::Bag;
54}
55
56impl<Bag: ConstantBag> AsBag for Bag {
57    type Bag = Self;
58    fn as_bag(self) -> Self {
59        self
60    }
61}
62
63#[derive(Clone, Copy)]
64pub struct BasicBag;
65
66impl ConstantBag for BasicBag {
67    type Constant = ConstantData;
68    fn make_constant<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant {
69        constant.to_owned()
70    }
71    fn make_int(&self, value: BigInt) -> Self::Constant {
72        ConstantData::Integer { value }
73    }
74    fn make_tuple(&self, elements: impl Iterator<Item = Self::Constant>) -> Self::Constant {
75        ConstantData::Tuple {
76            elements: elements.collect(),
77        }
78    }
79    fn make_code(&self, code: CodeObject<Self::Constant>) -> Self::Constant {
80        ConstantData::Code {
81            code: Box::new(code),
82        }
83    }
84    fn make_name(&self, name: &str) -> <Self::Constant as Constant>::Name {
85        name.to_owned()
86    }
87}
88
89/// Primary container of a single code object. Each python function has
90/// a code object. Also a module has a code object.
91#[derive(Clone)]
92pub struct CodeObject<C: Constant = ConstantData> {
93    pub instructions: Box<[CodeUnit]>,
94    pub locations: Box<[SourceLocation]>,
95    pub flags: CodeFlags,
96    pub posonlyarg_count: u32,
97    // Number of positional-only arguments
98    pub arg_count: u32,
99    pub kwonlyarg_count: u32,
100    pub source_path: C::Name,
101    pub first_line_number: Option<OneIndexed>,
102    pub max_stackdepth: u32,
103    pub obj_name: C::Name,
104    // Name of the object that created this code object
105    pub cell2arg: Option<Box<[i32]>>,
106    pub constants: Box<[C]>,
107    pub names: Box<[C::Name]>,
108    pub varnames: Box<[C::Name]>,
109    pub cellvars: Box<[C::Name]>,
110    pub freevars: Box<[C::Name]>,
111}
112
113bitflags! {
114    #[derive(Copy, Clone, Debug, PartialEq)]
115    pub struct CodeFlags: u16 {
116        const NEW_LOCALS = 0x01;
117        const IS_GENERATOR = 0x02;
118        const IS_COROUTINE = 0x04;
119        const HAS_VARARGS = 0x08;
120        const HAS_VARKEYWORDS = 0x10;
121        const IS_OPTIMIZED = 0x20;
122    }
123}
124
125impl CodeFlags {
126    pub const NAME_MAPPING: &'static [(&'static str, CodeFlags)] = &[
127        ("GENERATOR", CodeFlags::IS_GENERATOR),
128        ("COROUTINE", CodeFlags::IS_COROUTINE),
129        (
130            "ASYNC_GENERATOR",
131            Self::from_bits_truncate(Self::IS_GENERATOR.bits() | Self::IS_COROUTINE.bits()),
132        ),
133        ("VARARGS", CodeFlags::HAS_VARARGS),
134        ("VARKEYWORDS", CodeFlags::HAS_VARKEYWORDS),
135    ];
136}
137
138/// an opcode argument that may be extended by a prior ExtendedArg
139#[derive(Copy, Clone, PartialEq, Eq)]
140#[repr(transparent)]
141pub struct OpArgByte(pub u8);
142impl OpArgByte {
143    pub const fn null() -> Self {
144        OpArgByte(0)
145    }
146}
147impl fmt::Debug for OpArgByte {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        self.0.fmt(f)
150    }
151}
152
153/// a full 32-bit op_arg, including any possible ExtendedArg extension
154#[derive(Copy, Clone, Debug)]
155#[repr(transparent)]
156pub struct OpArg(pub u32);
157impl OpArg {
158    pub const fn null() -> Self {
159        OpArg(0)
160    }
161
162    /// Returns how many CodeUnits a instruction with this op_arg will be encoded as
163    #[inline]
164    pub fn instr_size(self) -> usize {
165        (self.0 > 0xff) as usize + (self.0 > 0xff_ff) as usize + (self.0 > 0xff_ff_ff) as usize + 1
166    }
167
168    /// returns the arg split into any necessary ExtendedArg components (in big-endian order) and
169    /// the arg for the real opcode itself
170    #[inline(always)]
171    pub fn split(self) -> (impl ExactSizeIterator<Item = OpArgByte>, OpArgByte) {
172        let mut it = self
173            .0
174            .to_le_bytes()
175            .map(OpArgByte)
176            .into_iter()
177            .take(self.instr_size());
178        let lo = it.next().unwrap();
179        (it.rev(), lo)
180    }
181}
182
183#[derive(Default, Copy, Clone)]
184#[repr(transparent)]
185pub struct OpArgState {
186    state: u32,
187}
188
189impl OpArgState {
190    #[inline(always)]
191    pub fn get(&mut self, ins: CodeUnit) -> (Instruction, OpArg) {
192        let arg = self.extend(ins.arg);
193        if ins.op != Instruction::ExtendedArg {
194            self.reset();
195        }
196        (ins.op, arg)
197    }
198    #[inline(always)]
199    pub fn extend(&mut self, arg: OpArgByte) -> OpArg {
200        self.state = self.state << 8 | u32::from(arg.0);
201        OpArg(self.state)
202    }
203    #[inline(always)]
204    pub fn reset(&mut self) {
205        self.state = 0
206    }
207}
208
209pub trait OpArgType: Copy {
210    fn from_op_arg(x: u32) -> Option<Self>;
211    fn to_op_arg(self) -> u32;
212}
213
214impl OpArgType for u32 {
215    #[inline(always)]
216    fn from_op_arg(x: u32) -> Option<Self> {
217        Some(x)
218    }
219    #[inline(always)]
220    fn to_op_arg(self) -> u32 {
221        self
222    }
223}
224
225impl OpArgType for bool {
226    #[inline(always)]
227    fn from_op_arg(x: u32) -> Option<Self> {
228        Some(x != 0)
229    }
230    #[inline(always)]
231    fn to_op_arg(self) -> u32 {
232        self as u32
233    }
234}
235
236macro_rules! op_arg_enum_impl {
237    (enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => {
238        impl OpArgType for $name {
239            fn to_op_arg(self) -> u32 {
240                self as u32
241            }
242            fn from_op_arg(x: u32) -> Option<Self> {
243                Some(match u8::try_from(x).ok()? {
244                    $($value => Self::$var,)*
245                    _ => return None,
246                })
247            }
248        }
249    };
250}
251
252macro_rules! op_arg_enum {
253    ($(#[$attr:meta])* $vis:vis enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => {
254        $(#[$attr])*
255        $vis enum $name {
256            $($(#[$var_attr])* $var = $value,)*
257        }
258
259        op_arg_enum_impl!(enum $name {
260            $($(#[$var_attr])* $var = $value,)*
261        });
262    };
263}
264
265#[derive(Copy, Clone)]
266pub struct Arg<T: OpArgType>(PhantomData<T>);
267
268impl<T: OpArgType> Arg<T> {
269    #[inline]
270    pub fn marker() -> Self {
271        Arg(PhantomData)
272    }
273    #[inline]
274    pub fn new(arg: T) -> (Self, OpArg) {
275        (Self(PhantomData), OpArg(arg.to_op_arg()))
276    }
277    #[inline]
278    pub fn new_single(arg: T) -> (Self, OpArgByte)
279    where
280        T: Into<u8>,
281    {
282        (Self(PhantomData), OpArgByte(arg.into()))
283    }
284    #[inline(always)]
285    pub fn get(self, arg: OpArg) -> T {
286        self.try_get(arg).unwrap()
287    }
288    #[inline(always)]
289    pub fn try_get(self, arg: OpArg) -> Option<T> {
290        T::from_op_arg(arg.0)
291    }
292    #[inline(always)]
293    /// # Safety
294    /// T::from_op_arg(self) must succeed
295    pub unsafe fn get_unchecked(self, arg: OpArg) -> T {
296        match T::from_op_arg(arg.0) {
297            Some(t) => t,
298            None => std::hint::unreachable_unchecked(),
299        }
300    }
301}
302
303impl<T: OpArgType> PartialEq for Arg<T> {
304    fn eq(&self, _: &Self) -> bool {
305        true
306    }
307}
308impl<T: OpArgType> Eq for Arg<T> {}
309
310impl<T: OpArgType> fmt::Debug for Arg<T> {
311    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312        write!(f, "Arg<{}>", std::any::type_name::<T>())
313    }
314}
315
316#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
317#[repr(transparent)]
318// XXX: if you add a new instruction that stores a Label, make sure to add it in
319// Instruction::label_arg
320pub struct Label(pub u32);
321
322impl OpArgType for Label {
323    #[inline(always)]
324    fn from_op_arg(x: u32) -> Option<Self> {
325        Some(Label(x))
326    }
327    #[inline(always)]
328    fn to_op_arg(self) -> u32 {
329        self.0
330    }
331}
332
333impl fmt::Display for Label {
334    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335        self.0.fmt(f)
336    }
337}
338
339impl OpArgType for ConversionFlag {
340    #[inline]
341    fn from_op_arg(x: u32) -> Option<Self> {
342        match x as u8 {
343            b's' => Some(ConversionFlag::Str),
344            b'a' => Some(ConversionFlag::Ascii),
345            b'r' => Some(ConversionFlag::Repr),
346            std::u8::MAX => Some(ConversionFlag::None),
347            _ => None,
348        }
349    }
350    #[inline]
351    fn to_op_arg(self) -> u32 {
352        self as i8 as u8 as u32
353    }
354}
355
356op_arg_enum!(
357    /// The kind of Raise that occurred.
358    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
359    #[repr(u8)]
360    pub enum RaiseKind {
361        Reraise = 0,
362        Raise = 1,
363        RaiseCause = 2,
364    }
365);
366
367pub type NameIdx = u32;
368
369/// A Single bytecode instruction.
370#[derive(Debug, Copy, Clone, PartialEq, Eq)]
371#[repr(u8)]
372pub enum Instruction {
373    /// Importing by name
374    ImportName {
375        idx: Arg<NameIdx>,
376    },
377    /// Importing without name
378    ImportNameless,
379    /// Import *
380    ImportStar,
381    /// from ... import ...
382    ImportFrom {
383        idx: Arg<NameIdx>,
384    },
385    LoadFast(Arg<NameIdx>),
386    LoadNameAny(Arg<NameIdx>),
387    LoadGlobal(Arg<NameIdx>),
388    LoadDeref(Arg<NameIdx>),
389    LoadClassDeref(Arg<NameIdx>),
390    StoreFast(Arg<NameIdx>),
391    StoreLocal(Arg<NameIdx>),
392    StoreGlobal(Arg<NameIdx>),
393    StoreDeref(Arg<NameIdx>),
394    DeleteFast(Arg<NameIdx>),
395    DeleteLocal(Arg<NameIdx>),
396    DeleteGlobal(Arg<NameIdx>),
397    DeleteDeref(Arg<NameIdx>),
398    LoadClosure(Arg<NameIdx>),
399    Subscript,
400    StoreSubscript,
401    DeleteSubscript,
402    StoreAttr {
403        idx: Arg<NameIdx>,
404    },
405    DeleteAttr {
406        idx: Arg<NameIdx>,
407    },
408    LoadConst {
409        /// index into constants vec
410        idx: Arg<u32>,
411    },
412    UnaryOperation {
413        op: Arg<UnaryOperator>,
414    },
415    BinaryOperation {
416        op: Arg<BinaryOperator>,
417    },
418    BinaryOperationInplace {
419        op: Arg<BinaryOperator>,
420    },
421    LoadAttr {
422        idx: Arg<NameIdx>,
423    },
424    TestOperation {
425        op: Arg<TestOperator>,
426    },
427    CompareOperation {
428        op: Arg<ComparisonOperator>,
429    },
430    Pop,
431    Rotate2,
432    Rotate3,
433    Duplicate,
434    Duplicate2,
435    GetIter,
436    Continue {
437        target: Arg<Label>,
438    },
439    Break {
440        target: Arg<Label>,
441    },
442    Jump {
443        target: Arg<Label>,
444    },
445    /// Pop the top of the stack, and jump if this value is true.
446    JumpIfTrue {
447        target: Arg<Label>,
448    },
449    /// Pop the top of the stack, and jump if this value is false.
450    JumpIfFalse {
451        target: Arg<Label>,
452    },
453    /// Peek at the top of the stack, and jump if this value is true.
454    /// Otherwise, pop top of stack.
455    JumpIfTrueOrPop {
456        target: Arg<Label>,
457    },
458    /// Peek at the top of the stack, and jump if this value is false.
459    /// Otherwise, pop top of stack.
460    JumpIfFalseOrPop {
461        target: Arg<Label>,
462    },
463    MakeFunction(Arg<MakeFunctionFlags>),
464    CallFunctionPositional {
465        nargs: Arg<u32>,
466    },
467    CallFunctionKeyword {
468        nargs: Arg<u32>,
469    },
470    CallFunctionEx {
471        has_kwargs: Arg<bool>,
472    },
473    LoadMethod {
474        idx: Arg<NameIdx>,
475    },
476    CallMethodPositional {
477        nargs: Arg<u32>,
478    },
479    CallMethodKeyword {
480        nargs: Arg<u32>,
481    },
482    CallMethodEx {
483        has_kwargs: Arg<bool>,
484    },
485    ForIter {
486        target: Arg<Label>,
487    },
488    ReturnValue,
489    ReturnConst {
490        idx: Arg<u32>,
491    },
492    YieldValue,
493    YieldFrom,
494    SetupAnnotation,
495    SetupLoop,
496
497    /// Setup a finally handler, which will be called whenever one of this events occurs:
498    /// - the block is popped
499    /// - the function returns
500    /// - an exception is returned
501    SetupFinally {
502        handler: Arg<Label>,
503    },
504
505    /// Enter a finally block, without returning, excepting, just because we are there.
506    EnterFinally,
507
508    /// Marker bytecode for the end of a finally sequence.
509    /// When this bytecode is executed, the eval loop does one of those things:
510    /// - Continue at a certain bytecode position
511    /// - Propagate the exception
512    /// - Return from a function
513    /// - Do nothing at all, just continue
514    EndFinally,
515
516    SetupExcept {
517        handler: Arg<Label>,
518    },
519    SetupWith {
520        end: Arg<Label>,
521    },
522    WithCleanupStart,
523    WithCleanupFinish,
524    PopBlock,
525    Raise {
526        kind: Arg<RaiseKind>,
527    },
528    BuildString {
529        size: Arg<u32>,
530    },
531    BuildTuple {
532        size: Arg<u32>,
533    },
534    BuildTupleUnpack {
535        size: Arg<u32>,
536    },
537    BuildList {
538        size: Arg<u32>,
539    },
540    BuildListUnpack {
541        size: Arg<u32>,
542    },
543    BuildSet {
544        size: Arg<u32>,
545    },
546    BuildSetUnpack {
547        size: Arg<u32>,
548    },
549    BuildMap {
550        size: Arg<u32>,
551    },
552    BuildMapForCall {
553        size: Arg<u32>,
554    },
555    DictUpdate,
556    BuildSlice {
557        /// whether build a slice with a third step argument
558        step: Arg<bool>,
559    },
560    ListAppend {
561        i: Arg<u32>,
562    },
563    SetAdd {
564        i: Arg<u32>,
565    },
566    MapAdd {
567        i: Arg<u32>,
568    },
569
570    PrintExpr,
571    LoadBuildClass,
572    UnpackSequence {
573        size: Arg<u32>,
574    },
575    UnpackEx {
576        args: Arg<UnpackExArgs>,
577    },
578    FormatValue {
579        conversion: Arg<ConversionFlag>,
580    },
581    PopException,
582    Reverse {
583        amount: Arg<u32>,
584    },
585    GetAwaitable,
586    BeforeAsyncWith,
587    SetupAsyncWith {
588        end: Arg<Label>,
589    },
590    GetAIter,
591    GetANext,
592    EndAsyncFor,
593    ExtendedArg,
594    TypeVar,
595    TypeVarWithBound,
596    TypeVarWithConstraint,
597    TypeAlias,
598    // If you add a new instruction here, be sure to keep LAST_INSTRUCTION updated
599}
600// This must be kept up to date to avoid marshaling errors
601const LAST_INSTRUCTION: Instruction = Instruction::TypeAlias;
602const _: () = assert!(mem::size_of::<Instruction>() == 1);
603
604impl From<Instruction> for u8 {
605    #[inline]
606    fn from(ins: Instruction) -> u8 {
607        // SAFETY: there's no padding bits
608        unsafe { std::mem::transmute::<Instruction, u8>(ins) }
609    }
610}
611
612impl TryFrom<u8> for Instruction {
613    type Error = crate::marshal::MarshalError;
614
615    #[inline]
616    fn try_from(value: u8) -> Result<Self, crate::marshal::MarshalError> {
617        if value <= u8::from(LAST_INSTRUCTION) {
618            Ok(unsafe { std::mem::transmute::<u8, Instruction>(value) })
619        } else {
620            Err(crate::marshal::MarshalError::InvalidBytecode)
621        }
622    }
623}
624
625#[derive(Copy, Clone)]
626#[repr(C)]
627pub struct CodeUnit {
628    pub op: Instruction,
629    pub arg: OpArgByte,
630}
631
632const _: () = assert!(mem::size_of::<CodeUnit>() == 2);
633
634impl CodeUnit {
635    pub fn new(op: Instruction, arg: OpArgByte) -> Self {
636        Self { op, arg }
637    }
638}
639
640use self::Instruction::*;
641
642bitflags! {
643    #[derive(Copy, Clone, Debug, PartialEq)]
644    pub struct MakeFunctionFlags: u8 {
645        const CLOSURE = 0x01;
646        const ANNOTATIONS = 0x02;
647        const KW_ONLY_DEFAULTS = 0x04;
648        const DEFAULTS = 0x08;
649        const TYPE_PARAMS = 0x10;
650    }
651}
652impl OpArgType for MakeFunctionFlags {
653    #[inline(always)]
654    fn from_op_arg(x: u32) -> Option<Self> {
655        MakeFunctionFlags::from_bits(x as u8)
656    }
657    #[inline(always)]
658    fn to_op_arg(self) -> u32 {
659        self.bits().into()
660    }
661}
662
663/// A Constant (which usually encapsulates data within it)
664///
665/// # Examples
666/// ```
667/// use rustpython_compiler_core::bytecode::ConstantData;
668/// let a = ConstantData::Float {value: 120f64};
669/// let b = ConstantData::Boolean {value: false};
670/// assert_ne!(a, b);
671/// ```
672#[derive(Debug, Clone)]
673pub enum ConstantData {
674    Tuple { elements: Vec<ConstantData> },
675    Integer { value: BigInt },
676    Float { value: f64 },
677    Complex { value: Complex64 },
678    Boolean { value: bool },
679    Str { value: String },
680    Bytes { value: Vec<u8> },
681    Code { code: Box<CodeObject> },
682    None,
683    Ellipsis,
684}
685
686impl PartialEq for ConstantData {
687    fn eq(&self, other: &Self) -> bool {
688        use ConstantData::*;
689        match (self, other) {
690            (Integer { value: a }, Integer { value: b }) => a == b,
691            // we want to compare floats *by actual value* - if we have the *exact same* float
692            // already in a constant cache, we want to use that
693            (Float { value: a }, Float { value: b }) => a.to_bits() == b.to_bits(),
694            (Complex { value: a }, Complex { value: b }) => {
695                a.re.to_bits() == b.re.to_bits() && a.im.to_bits() == b.im.to_bits()
696            }
697            (Boolean { value: a }, Boolean { value: b }) => a == b,
698            (Str { value: a }, Str { value: b }) => a == b,
699            (Bytes { value: a }, Bytes { value: b }) => a == b,
700            (Code { code: a }, Code { code: b }) => std::ptr::eq(a.as_ref(), b.as_ref()),
701            (Tuple { elements: a }, Tuple { elements: b }) => a == b,
702            (None, None) => true,
703            (Ellipsis, Ellipsis) => true,
704            _ => false,
705        }
706    }
707}
708
709impl Eq for ConstantData {}
710
711impl hash::Hash for ConstantData {
712    fn hash<H: hash::Hasher>(&self, state: &mut H) {
713        use ConstantData::*;
714        mem::discriminant(self).hash(state);
715        match self {
716            Integer { value } => value.hash(state),
717            Float { value } => value.to_bits().hash(state),
718            Complex { value } => {
719                value.re.to_bits().hash(state);
720                value.im.to_bits().hash(state);
721            }
722            Boolean { value } => value.hash(state),
723            Str { value } => value.hash(state),
724            Bytes { value } => value.hash(state),
725            Code { code } => std::ptr::hash(code.as_ref(), state),
726            Tuple { elements } => elements.hash(state),
727            None => {}
728            Ellipsis => {}
729        }
730    }
731}
732
733/// A borrowed Constant
734pub enum BorrowedConstant<'a, C: Constant> {
735    Integer { value: &'a BigInt },
736    Float { value: f64 },
737    Complex { value: Complex64 },
738    Boolean { value: bool },
739    Str { value: &'a str },
740    Bytes { value: &'a [u8] },
741    Code { code: &'a CodeObject<C> },
742    Tuple { elements: &'a [C] },
743    None,
744    Ellipsis,
745}
746
747impl<C: Constant> Copy for BorrowedConstant<'_, C> {}
748impl<C: Constant> Clone for BorrowedConstant<'_, C> {
749    fn clone(&self) -> Self {
750        *self
751    }
752}
753
754impl<C: Constant> BorrowedConstant<'_, C> {
755    pub fn fmt_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
756        match self {
757            BorrowedConstant::Integer { value } => write!(f, "{value}"),
758            BorrowedConstant::Float { value } => write!(f, "{value}"),
759            BorrowedConstant::Complex { value } => write!(f, "{value}"),
760            BorrowedConstant::Boolean { value } => {
761                write!(f, "{}", if *value { "True" } else { "False" })
762            }
763            BorrowedConstant::Str { value } => write!(f, "{value:?}"),
764            BorrowedConstant::Bytes { value } => write!(f, "b\"{}\"", value.escape_ascii()),
765            BorrowedConstant::Code { code } => write!(f, "{code:?}"),
766            BorrowedConstant::Tuple { elements } => {
767                write!(f, "(")?;
768                let mut first = true;
769                for c in *elements {
770                    if first {
771                        first = false
772                    } else {
773                        write!(f, ", ")?;
774                    }
775                    c.borrow_constant().fmt_display(f)?;
776                }
777                write!(f, ")")
778            }
779            BorrowedConstant::None => write!(f, "None"),
780            BorrowedConstant::Ellipsis => write!(f, "..."),
781        }
782    }
783    pub fn to_owned(self) -> ConstantData {
784        use ConstantData::*;
785        match self {
786            BorrowedConstant::Integer { value } => Integer {
787                value: value.clone(),
788            },
789            BorrowedConstant::Float { value } => Float { value },
790            BorrowedConstant::Complex { value } => Complex { value },
791            BorrowedConstant::Boolean { value } => Boolean { value },
792            BorrowedConstant::Str { value } => Str {
793                value: value.to_owned(),
794            },
795            BorrowedConstant::Bytes { value } => Bytes {
796                value: value.to_owned(),
797            },
798            BorrowedConstant::Code { code } => Code {
799                code: Box::new(code.map_clone_bag(&BasicBag)),
800            },
801            BorrowedConstant::Tuple { elements } => Tuple {
802                elements: elements
803                    .iter()
804                    .map(|c| c.borrow_constant().to_owned())
805                    .collect(),
806            },
807            BorrowedConstant::None => None,
808            BorrowedConstant::Ellipsis => Ellipsis,
809        }
810    }
811}
812
813op_arg_enum!(
814    /// The possible comparison operators
815    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
816    #[repr(u8)]
817    pub enum ComparisonOperator {
818        // be intentional with bits so that we can do eval_ord with just a bitwise and
819        // bits: | Equal | Greater | Less |
820        Less = 0b001,
821        Greater = 0b010,
822        NotEqual = 0b011,
823        Equal = 0b100,
824        LessOrEqual = 0b101,
825        GreaterOrEqual = 0b110,
826    }
827);
828
829op_arg_enum!(
830    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
831    #[repr(u8)]
832    pub enum TestOperator {
833        In = 0,
834        NotIn = 1,
835        Is = 2,
836        IsNot = 3,
837        /// two exceptions that match?
838        ExceptionMatch = 4,
839    }
840);
841
842op_arg_enum!(
843    /// The possible Binary operators
844    /// # Examples
845    ///
846    /// ```ignore
847    /// use rustpython_compiler_core::Instruction::BinaryOperation;
848    /// use rustpython_compiler_core::BinaryOperator::Add;
849    /// let op = BinaryOperation {op: Add};
850    /// ```
851    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
852    #[repr(u8)]
853    pub enum BinaryOperator {
854        Power = 0,
855        Multiply = 1,
856        MatrixMultiply = 2,
857        Divide = 3,
858        FloorDivide = 4,
859        Modulo = 5,
860        Add = 6,
861        Subtract = 7,
862        Lshift = 8,
863        Rshift = 9,
864        And = 10,
865        Xor = 11,
866        Or = 12,
867    }
868);
869
870op_arg_enum!(
871    /// The possible unary operators
872    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
873    #[repr(u8)]
874    pub enum UnaryOperator {
875        Not = 0,
876        Invert = 1,
877        Minus = 2,
878        Plus = 3,
879    }
880);
881
882#[derive(Copy, Clone)]
883pub struct UnpackExArgs {
884    pub before: u8,
885    pub after: u8,
886}
887
888impl OpArgType for UnpackExArgs {
889    #[inline(always)]
890    fn from_op_arg(x: u32) -> Option<Self> {
891        let [before, after, ..] = x.to_le_bytes();
892        Some(Self { before, after })
893    }
894    #[inline(always)]
895    fn to_op_arg(self) -> u32 {
896        u32::from_le_bytes([self.before, self.after, 0, 0])
897    }
898}
899impl fmt::Display for UnpackExArgs {
900    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901        write!(f, "before: {}, after: {}", self.before, self.after)
902    }
903}
904
905/*
906Maintain a stack of blocks on the VM.
907pub enum BlockType {
908    Loop,
909    Except,
910}
911*/
912
913/// Argument structure
914pub struct Arguments<'a, N: AsRef<str>> {
915    pub posonlyargs: &'a [N],
916    pub args: &'a [N],
917    pub vararg: Option<&'a N>,
918    pub kwonlyargs: &'a [N],
919    pub varkwarg: Option<&'a N>,
920}
921
922impl<N: AsRef<str>> fmt::Debug for Arguments<'_, N> {
923    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
924        macro_rules! fmt_slice {
925            ($x:expr) => {
926                format_args!("[{}]", $x.iter().map(AsRef::as_ref).format(", "))
927            };
928        }
929        f.debug_struct("Arguments")
930            .field("posonlyargs", &fmt_slice!(self.posonlyargs))
931            .field("args", &fmt_slice!(self.posonlyargs))
932            .field("vararg", &self.vararg.map(N::as_ref))
933            .field("kwonlyargs", &fmt_slice!(self.kwonlyargs))
934            .field("varkwarg", &self.varkwarg.map(N::as_ref))
935            .finish()
936    }
937}
938
939impl<C: Constant> CodeObject<C> {
940    /// Get all arguments of the code object
941    /// like inspect.getargs
942    pub fn arg_names(&self) -> Arguments<C::Name> {
943        let nargs = self.arg_count as usize;
944        let nkwargs = self.kwonlyarg_count as usize;
945        let mut varargs_pos = nargs + nkwargs;
946        let posonlyargs = &self.varnames[..self.posonlyarg_count as usize];
947        let args = &self.varnames[..nargs];
948        let kwonlyargs = &self.varnames[nargs..varargs_pos];
949
950        let vararg = if self.flags.contains(CodeFlags::HAS_VARARGS) {
951            let vararg = &self.varnames[varargs_pos];
952            varargs_pos += 1;
953            Some(vararg)
954        } else {
955            None
956        };
957        let varkwarg = if self.flags.contains(CodeFlags::HAS_VARKEYWORDS) {
958            Some(&self.varnames[varargs_pos])
959        } else {
960            None
961        };
962
963        Arguments {
964            posonlyargs,
965            args,
966            vararg,
967            kwonlyargs,
968            varkwarg,
969        }
970    }
971
972    /// Return the labels targeted by the instructions of this CodeObject
973    pub fn label_targets(&self) -> BTreeSet<Label> {
974        let mut label_targets = BTreeSet::new();
975        let mut arg_state = OpArgState::default();
976        for instruction in &*self.instructions {
977            let (instruction, arg) = arg_state.get(*instruction);
978            if let Some(l) = instruction.label_arg() {
979                label_targets.insert(l.get(arg));
980            }
981        }
982        label_targets
983    }
984
985    fn display_inner(
986        &self,
987        f: &mut fmt::Formatter,
988        expand_code_objects: bool,
989        level: usize,
990    ) -> fmt::Result {
991        let label_targets = self.label_targets();
992        let line_digits = (3).max(self.locations.last().unwrap().row.to_string().len());
993        let offset_digits = (4).max(self.instructions.len().to_string().len());
994        let mut last_line = OneIndexed::MAX;
995        let mut arg_state = OpArgState::default();
996        for (offset, &instruction) in self.instructions.iter().enumerate() {
997            let (instruction, arg) = arg_state.get(instruction);
998            // optional line number
999            let line = self.locations[offset].row;
1000            if line != last_line {
1001                if last_line != OneIndexed::MAX {
1002                    writeln!(f)?;
1003                }
1004                last_line = line;
1005                write!(f, "{line:line_digits$}")?;
1006            } else {
1007                for _ in 0..line_digits {
1008                    write!(f, " ")?;
1009                }
1010            }
1011            write!(f, " ")?;
1012
1013            // level indent
1014            for _ in 0..level {
1015                write!(f, "    ")?;
1016            }
1017
1018            // arrow and offset
1019            let arrow = if label_targets.contains(&Label(offset as u32)) {
1020                ">>"
1021            } else {
1022                "  "
1023            };
1024            write!(f, "{arrow} {offset:offset_digits$} ")?;
1025
1026            // instruction
1027            instruction.fmt_dis(arg, f, self, expand_code_objects, 21, level)?;
1028            writeln!(f)?;
1029        }
1030        Ok(())
1031    }
1032
1033    /// Recursively display this CodeObject
1034    pub fn display_expand_code_objects(&self) -> impl fmt::Display + '_ {
1035        struct Display<'a, C: Constant>(&'a CodeObject<C>);
1036        impl<C: Constant> fmt::Display for Display<'_, C> {
1037            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1038                self.0.display_inner(f, true, 1)
1039            }
1040        }
1041        Display(self)
1042    }
1043
1044    /// Map this CodeObject to one that holds a Bag::Constant
1045    pub fn map_bag<Bag: ConstantBag>(self, bag: Bag) -> CodeObject<Bag::Constant> {
1046        let map_names = |names: Box<[C::Name]>| {
1047            names
1048                .into_vec()
1049                .into_iter()
1050                .map(|x| bag.make_name(x.as_ref()))
1051                .collect::<Box<[_]>>()
1052        };
1053        CodeObject {
1054            constants: self
1055                .constants
1056                .into_vec()
1057                .into_iter()
1058                .map(|x| bag.make_constant(x.borrow_constant()))
1059                .collect(),
1060            names: map_names(self.names),
1061            varnames: map_names(self.varnames),
1062            cellvars: map_names(self.cellvars),
1063            freevars: map_names(self.freevars),
1064            source_path: bag.make_name(self.source_path.as_ref()),
1065            obj_name: bag.make_name(self.obj_name.as_ref()),
1066
1067            instructions: self.instructions,
1068            locations: self.locations,
1069            flags: self.flags,
1070            posonlyarg_count: self.posonlyarg_count,
1071            arg_count: self.arg_count,
1072            kwonlyarg_count: self.kwonlyarg_count,
1073            first_line_number: self.first_line_number,
1074            max_stackdepth: self.max_stackdepth,
1075            cell2arg: self.cell2arg,
1076        }
1077    }
1078
1079    /// Same as `map_bag` but clones `self`
1080    pub fn map_clone_bag<Bag: ConstantBag>(&self, bag: &Bag) -> CodeObject<Bag::Constant> {
1081        let map_names =
1082            |names: &[C::Name]| names.iter().map(|x| bag.make_name(x.as_ref())).collect();
1083        CodeObject {
1084            constants: self
1085                .constants
1086                .iter()
1087                .map(|x| bag.make_constant(x.borrow_constant()))
1088                .collect(),
1089            names: map_names(&self.names),
1090            varnames: map_names(&self.varnames),
1091            cellvars: map_names(&self.cellvars),
1092            freevars: map_names(&self.freevars),
1093            source_path: bag.make_name(self.source_path.as_ref()),
1094            obj_name: bag.make_name(self.obj_name.as_ref()),
1095
1096            instructions: self.instructions.clone(),
1097            locations: self.locations.clone(),
1098            flags: self.flags,
1099            posonlyarg_count: self.posonlyarg_count,
1100            arg_count: self.arg_count,
1101            kwonlyarg_count: self.kwonlyarg_count,
1102            first_line_number: self.first_line_number,
1103            max_stackdepth: self.max_stackdepth,
1104            cell2arg: self.cell2arg.clone(),
1105        }
1106    }
1107}
1108
1109impl<C: Constant> fmt::Display for CodeObject<C> {
1110    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1111        self.display_inner(f, false, 1)?;
1112        for constant in &*self.constants {
1113            if let BorrowedConstant::Code { code } = constant.borrow_constant() {
1114                writeln!(f, "\nDisassembly of {code:?}")?;
1115                code.fmt(f)?;
1116            }
1117        }
1118        Ok(())
1119    }
1120}
1121
1122impl Instruction {
1123    /// Gets the label stored inside this instruction, if it exists
1124    #[inline]
1125    pub fn label_arg(&self) -> Option<Arg<Label>> {
1126        match self {
1127            Jump { target: l }
1128            | JumpIfTrue { target: l }
1129            | JumpIfFalse { target: l }
1130            | JumpIfTrueOrPop { target: l }
1131            | JumpIfFalseOrPop { target: l }
1132            | ForIter { target: l }
1133            | SetupFinally { handler: l }
1134            | SetupExcept { handler: l }
1135            | SetupWith { end: l }
1136            | SetupAsyncWith { end: l }
1137            | Break { target: l }
1138            | Continue { target: l } => Some(*l),
1139            _ => None,
1140        }
1141    }
1142
1143    /// Whether this is an unconditional branching
1144    ///
1145    /// # Examples
1146    ///
1147    /// ```
1148    /// use rustpython_compiler_core::bytecode::{Arg, Instruction};
1149    /// let jump_inst = Instruction::Jump { target: Arg::marker() };
1150    /// assert!(jump_inst.unconditional_branch())
1151    /// ```
1152    pub fn unconditional_branch(&self) -> bool {
1153        matches!(
1154            self,
1155            Jump { .. }
1156                | Continue { .. }
1157                | Break { .. }
1158                | ReturnValue
1159                | ReturnConst { .. }
1160                | Raise { .. }
1161        )
1162    }
1163
1164    /// What effect this instruction has on the stack
1165    ///
1166    /// # Examples
1167    ///
1168    /// ```
1169    /// use rustpython_compiler_core::bytecode::{Arg, Instruction, Label, UnaryOperator};
1170    /// let (target, jump_arg) = Arg::new(Label(0xF));
1171    /// let jump_instruction = Instruction::Jump { target };
1172    /// let (op, invert_arg) = Arg::new(UnaryOperator::Invert);
1173    /// let invert_instruction = Instruction::UnaryOperation { op };
1174    /// assert_eq!(jump_instruction.stack_effect(jump_arg, true), 0);
1175    /// assert_eq!(invert_instruction.stack_effect(invert_arg, false), 0);
1176    /// ```
1177    ///
1178    pub fn stack_effect(&self, arg: OpArg, jump: bool) -> i32 {
1179        match self {
1180            ImportName { .. } | ImportNameless => -1,
1181            ImportStar => -1,
1182            ImportFrom { .. } => 1,
1183            LoadFast(_) | LoadNameAny(_) | LoadGlobal(_) | LoadDeref(_) | LoadClassDeref(_) => 1,
1184            StoreFast(_) | StoreLocal(_) | StoreGlobal(_) | StoreDeref(_) => -1,
1185            DeleteFast(_) | DeleteLocal(_) | DeleteGlobal(_) | DeleteDeref(_) => 0,
1186            LoadClosure(_) => 1,
1187            Subscript => -1,
1188            StoreSubscript => -3,
1189            DeleteSubscript => -2,
1190            LoadAttr { .. } => 0,
1191            StoreAttr { .. } => -2,
1192            DeleteAttr { .. } => -1,
1193            LoadConst { .. } => 1,
1194            UnaryOperation { .. } => 0,
1195            BinaryOperation { .. }
1196            | BinaryOperationInplace { .. }
1197            | TestOperation { .. }
1198            | CompareOperation { .. } => -1,
1199            Pop => -1,
1200            Rotate2 | Rotate3 => 0,
1201            Duplicate => 1,
1202            Duplicate2 => 2,
1203            GetIter => 0,
1204            Continue { .. } => 0,
1205            Break { .. } => 0,
1206            Jump { .. } => 0,
1207            JumpIfTrue { .. } | JumpIfFalse { .. } => -1,
1208            JumpIfTrueOrPop { .. } | JumpIfFalseOrPop { .. } => {
1209                if jump {
1210                    0
1211                } else {
1212                    -1
1213                }
1214            }
1215            MakeFunction(flags) => {
1216                let flags = flags.get(arg);
1217                -2 - flags.contains(MakeFunctionFlags::CLOSURE) as i32
1218                    - flags.contains(MakeFunctionFlags::ANNOTATIONS) as i32
1219                    - flags.contains(MakeFunctionFlags::KW_ONLY_DEFAULTS) as i32
1220                    - flags.contains(MakeFunctionFlags::DEFAULTS) as i32
1221                    + 1
1222            }
1223            CallFunctionPositional { nargs } => -(nargs.get(arg) as i32) - 1 + 1,
1224            CallMethodPositional { nargs } => -(nargs.get(arg) as i32) - 3 + 1,
1225            CallFunctionKeyword { nargs } => -1 - (nargs.get(arg) as i32) - 1 + 1,
1226            CallMethodKeyword { nargs } => -1 - (nargs.get(arg) as i32) - 3 + 1,
1227            CallFunctionEx { has_kwargs } => -1 - (has_kwargs.get(arg) as i32) - 1 + 1,
1228            CallMethodEx { has_kwargs } => -1 - (has_kwargs.get(arg) as i32) - 3 + 1,
1229            LoadMethod { .. } => -1 + 3,
1230            ForIter { .. } => {
1231                if jump {
1232                    -1
1233                } else {
1234                    1
1235                }
1236            }
1237            ReturnValue => -1,
1238            ReturnConst { .. } => 0,
1239            YieldValue => 0,
1240            YieldFrom => -1,
1241            SetupAnnotation | SetupLoop | SetupFinally { .. } | EnterFinally | EndFinally => 0,
1242            SetupExcept { .. } => jump as i32,
1243            SetupWith { .. } => (!jump) as i32,
1244            WithCleanupStart => 0,
1245            WithCleanupFinish => -1,
1246            PopBlock => 0,
1247            Raise { kind } => -(kind.get(arg) as u8 as i32),
1248            BuildString { size }
1249            | BuildTuple { size, .. }
1250            | BuildTupleUnpack { size, .. }
1251            | BuildList { size, .. }
1252            | BuildListUnpack { size, .. }
1253            | BuildSet { size, .. }
1254            | BuildSetUnpack { size, .. } => -(size.get(arg) as i32) + 1,
1255            BuildMap { size } => {
1256                let nargs = size.get(arg) * 2;
1257                -(nargs as i32) + 1
1258            }
1259            BuildMapForCall { size } => {
1260                let nargs = size.get(arg);
1261                -(nargs as i32) + 1
1262            }
1263            DictUpdate => -1,
1264            BuildSlice { step } => -2 - (step.get(arg) as i32) + 1,
1265            ListAppend { .. } | SetAdd { .. } => -1,
1266            MapAdd { .. } => -2,
1267            PrintExpr => -1,
1268            LoadBuildClass => 1,
1269            UnpackSequence { size } => -1 + size.get(arg) as i32,
1270            UnpackEx { args } => {
1271                let UnpackExArgs { before, after } = args.get(arg);
1272                -1 + before as i32 + 1 + after as i32
1273            }
1274            FormatValue { .. } => -1,
1275            PopException => 0,
1276            Reverse { .. } => 0,
1277            GetAwaitable => 0,
1278            BeforeAsyncWith => 1,
1279            SetupAsyncWith { .. } => {
1280                if jump {
1281                    -1
1282                } else {
1283                    0
1284                }
1285            }
1286            GetAIter => 0,
1287            GetANext => 1,
1288            EndAsyncFor => -2,
1289            ExtendedArg => 0,
1290            TypeVar => 0,
1291            TypeVarWithBound => -1,
1292            TypeVarWithConstraint => -1,
1293            TypeAlias => -2,
1294        }
1295    }
1296
1297    pub fn display<'a>(
1298        &'a self,
1299        arg: OpArg,
1300        ctx: &'a impl InstrDisplayContext,
1301    ) -> impl fmt::Display + 'a {
1302        struct FmtFn<F>(F);
1303        impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> fmt::Display for FmtFn<F> {
1304            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1305                (self.0)(f)
1306            }
1307        }
1308        FmtFn(move |f: &mut fmt::Formatter| self.fmt_dis(arg, f, ctx, false, 0, 0))
1309    }
1310
1311    #[allow(clippy::too_many_arguments)]
1312    fn fmt_dis(
1313        &self,
1314        arg: OpArg,
1315        f: &mut fmt::Formatter,
1316        ctx: &impl InstrDisplayContext,
1317        expand_code_objects: bool,
1318        pad: usize,
1319        level: usize,
1320    ) -> fmt::Result {
1321        macro_rules! w {
1322            ($variant:ident) => {
1323                write!(f, stringify!($variant))
1324            };
1325            ($variant:ident, $map:ident = $arg_marker:expr) => {{
1326                let arg = $arg_marker.get(arg);
1327                write!(f, "{:pad$}({}, {})", stringify!($variant), arg, $map(arg))
1328            }};
1329            ($variant:ident, $arg_marker:expr) => {
1330                write!(f, "{:pad$}({})", stringify!($variant), $arg_marker.get(arg))
1331            };
1332            ($variant:ident, ?$arg_marker:expr) => {
1333                write!(
1334                    f,
1335                    "{:pad$}({:?})",
1336                    stringify!($variant),
1337                    $arg_marker.get(arg)
1338                )
1339            };
1340        }
1341
1342        let varname = |i: u32| ctx.get_varname(i as usize);
1343        let name = |i: u32| ctx.get_name(i as usize);
1344        let cell_name = |i: u32| ctx.get_cell_name(i as usize);
1345
1346        let fmt_const =
1347            |op: &str, arg: OpArg, f: &mut fmt::Formatter, idx: &Arg<u32>| -> fmt::Result {
1348                let value = ctx.get_constant(idx.get(arg) as usize);
1349                match value.borrow_constant() {
1350                    BorrowedConstant::Code { code } if expand_code_objects => {
1351                        write!(f, "{:pad$}({:?}):", op, code)?;
1352                        code.display_inner(f, true, level + 1)?;
1353                        Ok(())
1354                    }
1355                    c => {
1356                        write!(f, "{:pad$}(", op)?;
1357                        c.fmt_display(f)?;
1358                        write!(f, ")")
1359                    }
1360                }
1361            };
1362
1363        match self {
1364            ImportName { idx } => w!(ImportName, name = idx),
1365            ImportNameless => w!(ImportNameless),
1366            ImportStar => w!(ImportStar),
1367            ImportFrom { idx } => w!(ImportFrom, name = idx),
1368            LoadFast(idx) => w!(LoadFast, varname = idx),
1369            LoadNameAny(idx) => w!(LoadNameAny, name = idx),
1370            LoadGlobal(idx) => w!(LoadGlobal, name = idx),
1371            LoadDeref(idx) => w!(LoadDeref, cell_name = idx),
1372            LoadClassDeref(idx) => w!(LoadClassDeref, cell_name = idx),
1373            StoreFast(idx) => w!(StoreFast, varname = idx),
1374            StoreLocal(idx) => w!(StoreLocal, name = idx),
1375            StoreGlobal(idx) => w!(StoreGlobal, name = idx),
1376            StoreDeref(idx) => w!(StoreDeref, cell_name = idx),
1377            DeleteFast(idx) => w!(DeleteFast, varname = idx),
1378            DeleteLocal(idx) => w!(DeleteLocal, name = idx),
1379            DeleteGlobal(idx) => w!(DeleteGlobal, name = idx),
1380            DeleteDeref(idx) => w!(DeleteDeref, cell_name = idx),
1381            LoadClosure(i) => w!(LoadClosure, cell_name = i),
1382            Subscript => w!(Subscript),
1383            StoreSubscript => w!(StoreSubscript),
1384            DeleteSubscript => w!(DeleteSubscript),
1385            StoreAttr { idx } => w!(StoreAttr, name = idx),
1386            DeleteAttr { idx } => w!(DeleteAttr, name = idx),
1387            LoadConst { idx } => fmt_const("LoadConst", arg, f, idx),
1388            UnaryOperation { op } => w!(UnaryOperation, ?op),
1389            BinaryOperation { op } => w!(BinaryOperation, ?op),
1390            BinaryOperationInplace { op } => w!(BinaryOperationInplace, ?op),
1391            LoadAttr { idx } => w!(LoadAttr, name = idx),
1392            TestOperation { op } => w!(TestOperation, ?op),
1393            CompareOperation { op } => w!(CompareOperation, ?op),
1394            Pop => w!(Pop),
1395            Rotate2 => w!(Rotate2),
1396            Rotate3 => w!(Rotate3),
1397            Duplicate => w!(Duplicate),
1398            Duplicate2 => w!(Duplicate2),
1399            GetIter => w!(GetIter),
1400            Continue { target } => w!(Continue, target),
1401            Break { target } => w!(Break, target),
1402            Jump { target } => w!(Jump, target),
1403            JumpIfTrue { target } => w!(JumpIfTrue, target),
1404            JumpIfFalse { target } => w!(JumpIfFalse, target),
1405            JumpIfTrueOrPop { target } => w!(JumpIfTrueOrPop, target),
1406            JumpIfFalseOrPop { target } => w!(JumpIfFalseOrPop, target),
1407            MakeFunction(flags) => w!(MakeFunction, ?flags),
1408            CallFunctionPositional { nargs } => w!(CallFunctionPositional, nargs),
1409            CallFunctionKeyword { nargs } => w!(CallFunctionKeyword, nargs),
1410            CallFunctionEx { has_kwargs } => w!(CallFunctionEx, has_kwargs),
1411            LoadMethod { idx } => w!(LoadMethod, name = idx),
1412            CallMethodPositional { nargs } => w!(CallMethodPositional, nargs),
1413            CallMethodKeyword { nargs } => w!(CallMethodKeyword, nargs),
1414            CallMethodEx { has_kwargs } => w!(CallMethodEx, has_kwargs),
1415            ForIter { target } => w!(ForIter, target),
1416            ReturnValue => w!(ReturnValue),
1417            ReturnConst { idx } => fmt_const("ReturnConst", arg, f, idx),
1418            YieldValue => w!(YieldValue),
1419            YieldFrom => w!(YieldFrom),
1420            SetupAnnotation => w!(SetupAnnotation),
1421            SetupLoop => w!(SetupLoop),
1422            SetupExcept { handler } => w!(SetupExcept, handler),
1423            SetupFinally { handler } => w!(SetupFinally, handler),
1424            EnterFinally => w!(EnterFinally),
1425            EndFinally => w!(EndFinally),
1426            SetupWith { end } => w!(SetupWith, end),
1427            WithCleanupStart => w!(WithCleanupStart),
1428            WithCleanupFinish => w!(WithCleanupFinish),
1429            BeforeAsyncWith => w!(BeforeAsyncWith),
1430            SetupAsyncWith { end } => w!(SetupAsyncWith, end),
1431            PopBlock => w!(PopBlock),
1432            Raise { kind } => w!(Raise, ?kind),
1433            BuildString { size } => w!(BuildString, size),
1434            BuildTuple { size } => w!(BuildTuple, size),
1435            BuildTupleUnpack { size } => w!(BuildTupleUnpack, size),
1436            BuildList { size } => w!(BuildList, size),
1437            BuildListUnpack { size } => w!(BuildListUnpack, size),
1438            BuildSet { size } => w!(BuildSet, size),
1439            BuildSetUnpack { size } => w!(BuildSetUnpack, size),
1440            BuildMap { size } => w!(BuildMap, size),
1441            BuildMapForCall { size } => w!(BuildMap, size),
1442            DictUpdate => w!(DictUpdate),
1443            BuildSlice { step } => w!(BuildSlice, step),
1444            ListAppend { i } => w!(ListAppend, i),
1445            SetAdd { i } => w!(SetAdd, i),
1446            MapAdd { i } => w!(MapAdd, i),
1447            PrintExpr => w!(PrintExpr),
1448            LoadBuildClass => w!(LoadBuildClass),
1449            UnpackSequence { size } => w!(UnpackSequence, size),
1450            UnpackEx { args } => w!(UnpackEx, args),
1451            FormatValue { conversion } => w!(FormatValue, ?conversion),
1452            PopException => w!(PopException),
1453            Reverse { amount } => w!(Reverse, amount),
1454            GetAwaitable => w!(GetAwaitable),
1455            GetAIter => w!(GetAIter),
1456            GetANext => w!(GetANext),
1457            EndAsyncFor => w!(EndAsyncFor),
1458            ExtendedArg => w!(ExtendedArg, Arg::<u32>::marker()),
1459            TypeVar => w!(TypeVar),
1460            TypeVarWithBound => w!(TypeVarWithBound),
1461            TypeVarWithConstraint => w!(TypeVarWithConstraint),
1462            TypeAlias => w!(TypeAlias),
1463        }
1464    }
1465}
1466
1467pub trait InstrDisplayContext {
1468    type Constant: Constant;
1469    fn get_constant(&self, i: usize) -> &Self::Constant;
1470    fn get_name(&self, i: usize) -> &str;
1471    fn get_varname(&self, i: usize) -> &str;
1472    fn get_cell_name(&self, i: usize) -> &str;
1473}
1474
1475impl<C: Constant> InstrDisplayContext for CodeObject<C> {
1476    type Constant = C;
1477    fn get_constant(&self, i: usize) -> &C {
1478        &self.constants[i]
1479    }
1480    fn get_name(&self, i: usize) -> &str {
1481        self.names[i].as_ref()
1482    }
1483    fn get_varname(&self, i: usize) -> &str {
1484        self.varnames[i].as_ref()
1485    }
1486    fn get_cell_name(&self, i: usize) -> &str {
1487        self.cellvars
1488            .get(i)
1489            .unwrap_or_else(|| &self.freevars[i - self.cellvars.len()])
1490            .as_ref()
1491    }
1492}
1493
1494impl fmt::Display for ConstantData {
1495    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1496        self.borrow_constant().fmt_display(f)
1497    }
1498}
1499
1500impl<C: Constant> fmt::Debug for CodeObject<C> {
1501    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1502        write!(
1503            f,
1504            "<code object {} at ??? file {:?}, line {}>",
1505            self.obj_name.as_ref(),
1506            self.source_path.as_ref(),
1507            self.first_line_number.map_or(-1, |x| x.get() as i32)
1508        )
1509    }
1510}