1use 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 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
40pub 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#[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 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 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#[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#[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 #[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 #[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 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)]
318pub 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 #[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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
371#[repr(u8)]
372pub enum Instruction {
373 ImportName {
375 idx: Arg<NameIdx>,
376 },
377 ImportNameless,
379 ImportStar,
381 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 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 JumpIfTrue {
447 target: Arg<Label>,
448 },
449 JumpIfFalse {
451 target: Arg<Label>,
452 },
453 JumpIfTrueOrPop {
456 target: Arg<Label>,
457 },
458 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 SetupFinally {
502 handler: Arg<Label>,
503 },
504
505 EnterFinally,
507
508 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 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 }
600const 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 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#[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 (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
733pub 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 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
816 #[repr(u8)]
817 pub enum ComparisonOperator {
818 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 ExceptionMatch = 4,
839 }
840);
841
842op_arg_enum!(
843 #[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 #[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
905pub 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 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 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 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 for _ in 0..level {
1015 write!(f, " ")?;
1016 }
1017
1018 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.fmt_dis(arg, f, self, expand_code_objects, 21, level)?;
1028 writeln!(f)?;
1029 }
1030 Ok(())
1031 }
1032
1033 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 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 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 #[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 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 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}