From e1763fcb9da08b5115514ac9dd9c354d2ee63741 Mon Sep 17 00:00:00 2001 From: Eric van der Toorn Date: Fri, 26 Mar 2021 21:58:34 +0100 Subject: [PATCH 1/8] 'float' --- common/src/float_ops.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/common/src/float_ops.rs b/common/src/float_ops.rs index 731258d9b..5f006180d 100644 --- a/common/src/float_ops.rs +++ b/common/src/float_ops.rs @@ -1,6 +1,7 @@ use num_bigint::{BigInt, ToBigInt}; use num_traits::{Float, Signed, ToPrimitive, Zero}; +/// pub fn ufrexp(value: f64) -> (f64, i32) { if 0.0 == value { (0.0, 0i32) @@ -12,6 +13,22 @@ pub fn ufrexp(value: f64) -> (f64, i32) { } } +/// Equate an integer to a float. +/// +/// Returns true if and only if, when converted to each others types, both are equal. +/// +/// # Examples +/// +/// ``` +/// use num_bigint::BigInt; +/// use rustpython_common::float_ops::eq_int; +/// let a = 1.0f64; +/// let b = BigInt::from(1); +/// let c = 2.0f64; +/// assert!(eq_int(a, &b)); +/// assert!(!eq_int(c, &b)); +/// ``` +/// pub fn eq_int(value: f64, other: &BigInt) -> bool { if let (Some(self_int), Some(other_float)) = (value.to_bigint(), other.to_f64()) { value == other_float && self_int == *other From 99740d1e8563ae52724466724a7b480d174c1994 Mon Sep 17 00:00:00 2001 From: Eric van der Toorn Date: Sat, 27 Mar 2021 14:46:31 +0100 Subject: [PATCH 2/8] add documentation to most public parts of bytecode, along with examples --- bytecode/src/lib.rs | 140 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 121 insertions(+), 19 deletions(-) diff --git a/bytecode/src/lib.rs b/bytecode/src/lib.rs index 73e2e173d..afc17e93d 100644 --- a/bytecode/src/lib.rs +++ b/bytecode/src/lib.rs @@ -14,6 +14,7 @@ use std::collections::BTreeSet; use std::{fmt, hash}; /// Sourcecode location. +/// TODO start, end, middle? #[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Location { row: usize, @@ -21,28 +22,47 @@ pub struct Location { } impl Location { + /// Creates a new Location object at the given row and column. + /// + /// # Example + /// ``` + /// use rustpython_bytecode::Location; + /// let loc = Location::new(10, 10); + /// ``` pub fn new(row: usize, column: usize) -> Self { Location { row, column } } + /// Current row pub fn row(&self) -> usize { self.row } + /// Current column pub fn column(&self) -> usize { self.column } } +/// A Constant object is +/// TODO unclear pub trait Constant: Sized { type Name: AsRef; + + /// Tranforms the given Constant to a BorrowedConstant fn borrow_constant(&self) -> BorrowedConstant; + /// Get the data this Constant holds. fn into_data(self) -> ConstantData { self.borrow_constant().into_data() } + /// Map this Constant to a Bag's constant + /// + /// TODO Unclear. fn map_constant(self, bag: &Bag) -> Bag::Constant { bag.make_constant(self.into_data()) } + + /// Maps the name for the given Bag. fn map_name( name: Self::Name, bag: &Bag, @@ -50,6 +70,7 @@ pub trait Constant: Sized { bag.make_name_ref(name.as_ref()) } } + impl Constant for ConstantData { type Name = String; fn borrow_constant(&self) -> BorrowedConstant { @@ -77,6 +98,7 @@ impl Constant for ConstantData { } } +/// A Constant Bag pub trait ConstantBag: Sized { type Constant: Constant; fn make_constant(&self, constant: ConstantData) -> Self::Constant; @@ -91,6 +113,7 @@ pub trait ConstantBag: Sized { #[derive(Clone)] pub struct BasicBag; + impl ConstantBag for BasicBag { type Constant = ConstantData; fn make_constant(&self, constant: ConstantData) -> Self::Constant { @@ -108,18 +131,20 @@ pub struct CodeObject { pub instructions: Box<[Instruction]>, pub locations: Box<[Location]>, pub flags: CodeFlags, - pub posonlyarg_count: usize, // Number of positional-only arguments + pub posonlyarg_count: usize, + // Number of positional-only arguments pub arg_count: usize, pub kwonlyarg_count: usize, pub source_path: C::Name, pub first_line_number: usize, pub max_stacksize: u32, - pub obj_name: C::Name, // Name of the object that created this code object + pub obj_name: C::Name, + // Name of the object that created this code object pub cell2arg: Option>, pub constants: Box<[C]>, #[serde(bound( - deserialize = "C::Name: serde::Deserialize<'de>", - serialize = "C::Name: serde::Serialize" + deserialize = "C::Name: serde::Deserialize<'de>", + serialize = "C::Name: serde::Serialize" ))] pub names: Box<[C::Name]>, pub varnames: Box<[C::Name]>, @@ -157,6 +182,7 @@ impl CodeFlags { // XXX: if you add a new instruction that stores a Label, make sure to add it in // Instruction::label_arg{,_mut} pub struct Label(pub u32); + impl fmt::Display for Label { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -176,6 +202,7 @@ pub enum ConversionFlag { Repr, } +/// The kind of Raise that occurred. #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum RaiseKind { Reraise, @@ -188,11 +215,15 @@ pub type NameIdx = u32; /// A Single bytecode instruction. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Instruction { + /// Importing by name ImportName { idx: NameIdx, }, + /// Importing without name ImportNameless, + /// Import * ImportStar, + /// from ... import ... ImportFrom { idx: NameIdx, }, @@ -400,6 +431,15 @@ bitflags! { } } +/// A Constant (which usually encapsulates data within it) +/// +/// # Examples +/// ``` +/// use rustpython_bytecode::ConstantData; +/// let a = ConstantData::Float {value: 120f64}; +/// let b = ConstantData::Boolean {value: false}; +/// assert_ne!(a, b); +/// ``` #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ConstantData { Tuple { elements: Vec }, @@ -436,6 +476,7 @@ impl PartialEq for ConstantData { } } } + impl Eq for ConstantData {} impl hash::Hash for ConstantData { @@ -460,6 +501,7 @@ impl hash::Hash for ConstantData { } } +/// A borrowed Constant pub enum BorrowedConstant<'a, C: Constant> { Integer { value: &'a BigInt }, Float { value: f64 }, @@ -472,7 +514,9 @@ pub enum BorrowedConstant<'a, C: Constant> { None, Ellipsis, } -type BorrowedTupleIter<'a, C> = Box> + 'a>; + +type BorrowedTupleIter<'a, C> = Box> + 'a>; + impl BorrowedConstant<'_, C> { // takes `self` because we need to consume the iterator pub fn fmt_display(self, f: &mut fmt::Formatter) -> fmt::Result { @@ -530,6 +574,7 @@ impl BorrowedConstant<'_, C> { } } +/// The possible comparison operators #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum ComparisonOperator { Greater, @@ -542,9 +587,19 @@ pub enum ComparisonOperator { NotIn, Is, IsNot, + /// two exceptions that match? + /// TODO clarify ExceptionMatch, } +/// The possible Binary operators +/// # Examples +/// +/// ``` +/// use rustpython_bytecode::Instruction::BinaryOperation; +/// use rustpython_bytecode::BinaryOperator::Add; +/// let op = BinaryOperation {op: Add}; +/// ``` #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum BinaryOperator { Power, @@ -562,6 +617,7 @@ pub enum BinaryOperator { Or, } +/// The possible unary operators #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum UnaryOperator { Not, @@ -578,6 +634,8 @@ pub enum BlockType { } */ +/// Argument structure +/// TODO is this for parameters or arguments? pub struct Arguments<'a, N: AsRef> { pub posonlyargs: &'a [N], pub args: &'a [N], @@ -604,7 +662,12 @@ impl> fmt::Debug for Arguments<'_, N> { } impl CodeObject { - // like inspect.getargs + /// Get all arguments of the code object + /// like inspect.getargs + /// # Examples + /// + /// TODO I'm not sure what is the best way to construct a CodeObject + /// pub fn arg_names(&self) -> Arguments { let nargs = self.arg_count; let nkwargs = self.kwonlyarg_count; @@ -635,6 +698,7 @@ impl CodeObject { } } + /// Return the labels targeted by the instructions of this CodeObject pub fn label_targets(&self) -> BTreeSet