mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-23 04:55:25 +00:00
reorganize compiler crates
This commit is contained in:
parent
3351b4408b
commit
060d153bb3
82 changed files with 12368 additions and 164 deletions
1282
ast/src/ast_gen.rs
Normal file
1282
ast/src/ast_gen.rs
Normal file
File diff suppressed because it is too large
Load diff
223
ast/src/constant.rs
Normal file
223
ast/src/constant.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
use num_bigint::BigInt;
|
||||
pub use rustpython_bytecode::ConversionFlag;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Constant {
|
||||
None,
|
||||
Bool(bool),
|
||||
Str(String),
|
||||
Bytes(Vec<u8>),
|
||||
Int(BigInt),
|
||||
Tuple(Vec<Constant>),
|
||||
Float(f64),
|
||||
Complex { real: f64, imag: f64 },
|
||||
Ellipsis,
|
||||
}
|
||||
|
||||
impl From<String> for Constant {
|
||||
fn from(s: String) -> Constant {
|
||||
Self::Str(s)
|
||||
}
|
||||
}
|
||||
impl From<Vec<u8>> for Constant {
|
||||
fn from(b: Vec<u8>) -> Constant {
|
||||
Self::Bytes(b)
|
||||
}
|
||||
}
|
||||
impl From<bool> for Constant {
|
||||
fn from(b: bool) -> Constant {
|
||||
Self::Bool(b)
|
||||
}
|
||||
}
|
||||
impl From<BigInt> for Constant {
|
||||
fn from(i: BigInt) -> Constant {
|
||||
Self::Int(i)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustpython-common")]
|
||||
impl std::fmt::Display for Constant {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Constant::None => f.pad("None"),
|
||||
Constant::Bool(b) => f.pad(if *b { "True" } else { "False" }),
|
||||
Constant::Str(s) => rustpython_common::str::repr(s).fmt(f),
|
||||
Constant::Bytes(b) => f.pad(&rustpython_common::bytes::repr(b)),
|
||||
Constant::Int(i) => i.fmt(f),
|
||||
Constant::Tuple(tup) => {
|
||||
if let [elt] = &**tup {
|
||||
write!(f, "({},)", elt)
|
||||
} else {
|
||||
f.write_str("(")?;
|
||||
for (i, elt) in tup.iter().enumerate() {
|
||||
if i != 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
elt.fmt(f)?;
|
||||
}
|
||||
f.write_str(")")
|
||||
}
|
||||
}
|
||||
Constant::Float(fp) => f.pad(&rustpython_common::float_ops::to_string(*fp)),
|
||||
Constant::Complex { real, imag } => {
|
||||
if *real == 0.0 {
|
||||
write!(f, "{}j", imag)
|
||||
} else {
|
||||
write!(f, "({}{:+}j)", real, imag)
|
||||
}
|
||||
}
|
||||
Constant::Ellipsis => f.pad("..."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "constant-optimization")]
|
||||
#[non_exhaustive]
|
||||
#[derive(Default)]
|
||||
pub struct ConstantOptimizer {}
|
||||
|
||||
#[cfg(feature = "constant-optimization")]
|
||||
impl ConstantOptimizer {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "constant-optimization")]
|
||||
impl<U> crate::fold::Fold<U> for ConstantOptimizer {
|
||||
type TargetU = U;
|
||||
type Error = std::convert::Infallible;
|
||||
#[inline]
|
||||
fn map_user(&mut self, user: U) -> Result<Self::TargetU, Self::Error> {
|
||||
Ok(user)
|
||||
}
|
||||
fn fold_expr(&mut self, node: crate::Expr<U>) -> Result<crate::Expr<U>, Self::Error> {
|
||||
match node.node {
|
||||
crate::ExprKind::Tuple { elts, ctx } => {
|
||||
let elts = elts
|
||||
.into_iter()
|
||||
.map(|x| self.fold_expr(x))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let expr = if elts
|
||||
.iter()
|
||||
.all(|e| matches!(e.node, crate::ExprKind::Constant { .. }))
|
||||
{
|
||||
let tuple = elts
|
||||
.into_iter()
|
||||
.map(|e| match e.node {
|
||||
crate::ExprKind::Constant { value, .. } => value,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
crate::ExprKind::Constant {
|
||||
value: Constant::Tuple(tuple),
|
||||
kind: None,
|
||||
}
|
||||
} else {
|
||||
crate::ExprKind::Tuple { elts, ctx }
|
||||
};
|
||||
Ok(crate::Expr {
|
||||
node: expr,
|
||||
custom: node.custom,
|
||||
location: node.location,
|
||||
})
|
||||
}
|
||||
_ => crate::fold::fold_expr(self, node),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "constant-optimization")]
|
||||
#[test]
|
||||
fn test_constant_opt() {
|
||||
use super::*;
|
||||
use crate::fold::Fold;
|
||||
use crate::*;
|
||||
|
||||
let location = Location::new(0, 0);
|
||||
let custom = ();
|
||||
let ast = Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Tuple {
|
||||
ctx: ExprContext::Load,
|
||||
elts: vec![
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: BigInt::from(1).into(),
|
||||
kind: None,
|
||||
},
|
||||
},
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: BigInt::from(2).into(),
|
||||
kind: None,
|
||||
},
|
||||
},
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Tuple {
|
||||
ctx: ExprContext::Load,
|
||||
elts: vec![
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: BigInt::from(3).into(),
|
||||
kind: None,
|
||||
},
|
||||
},
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: BigInt::from(4).into(),
|
||||
kind: None,
|
||||
},
|
||||
},
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: BigInt::from(5).into(),
|
||||
kind: None,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
let new_ast = ConstantOptimizer::new()
|
||||
.fold_expr(ast)
|
||||
.unwrap_or_else(|e| match e {});
|
||||
assert_eq!(
|
||||
new_ast,
|
||||
Located {
|
||||
location,
|
||||
custom,
|
||||
node: ExprKind::Constant {
|
||||
value: Constant::Tuple(vec![
|
||||
BigInt::from(1).into(),
|
||||
BigInt::from(2).into(),
|
||||
Constant::Tuple(vec![
|
||||
BigInt::from(3).into(),
|
||||
BigInt::from(4).into(),
|
||||
BigInt::from(5).into(),
|
||||
])
|
||||
]),
|
||||
kind: None
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
66
ast/src/fold_helpers.rs
Normal file
66
ast/src/fold_helpers.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::constant;
|
||||
use crate::fold::Fold;
|
||||
|
||||
pub(crate) trait Foldable<T, U> {
|
||||
type Mapped;
|
||||
fn fold<F: Fold<T, TargetU = U> + ?Sized>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self::Mapped, F::Error>;
|
||||
}
|
||||
|
||||
impl<T, U, X> Foldable<T, U> for Vec<X>
|
||||
where
|
||||
X: Foldable<T, U>,
|
||||
{
|
||||
type Mapped = Vec<X::Mapped>;
|
||||
fn fold<F: Fold<T, TargetU = U> + ?Sized>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self::Mapped, F::Error> {
|
||||
self.into_iter().map(|x| x.fold(folder)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, X> Foldable<T, U> for Option<X>
|
||||
where
|
||||
X: Foldable<T, U>,
|
||||
{
|
||||
type Mapped = Option<X::Mapped>;
|
||||
fn fold<F: Fold<T, TargetU = U> + ?Sized>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self::Mapped, F::Error> {
|
||||
self.map(|x| x.fold(folder)).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U, X> Foldable<T, U> for Box<X>
|
||||
where
|
||||
X: Foldable<T, U>,
|
||||
{
|
||||
type Mapped = Box<X::Mapped>;
|
||||
fn fold<F: Fold<T, TargetU = U> + ?Sized>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self::Mapped, F::Error> {
|
||||
(*self).fold(folder).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! simple_fold {
|
||||
($($t:ty),+$(,)?) => {
|
||||
$(impl<T, U> $crate::fold_helpers::Foldable<T, U> for $t {
|
||||
type Mapped = Self;
|
||||
#[inline]
|
||||
fn fold<F: Fold<T, TargetU = U> + ?Sized>(
|
||||
self,
|
||||
_folder: &mut F,
|
||||
) -> Result<Self::Mapped, F::Error> {
|
||||
Ok(self)
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
simple_fold!(usize, String, bool, constant::Constant);
|
60
ast/src/impls.rs
Normal file
60
ast/src/impls.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use crate::{Constant, ExprKind};
|
||||
|
||||
impl<U> ExprKind<U> {
|
||||
/// Returns a short name for the node suitable for use in error messages.
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
ExprKind::BoolOp { .. } | ExprKind::BinOp { .. } | ExprKind::UnaryOp { .. } => {
|
||||
"operator"
|
||||
}
|
||||
ExprKind::Subscript { .. } => "subscript",
|
||||
ExprKind::Await { .. } => "await expression",
|
||||
ExprKind::Yield { .. } | ExprKind::YieldFrom { .. } => "yield expression",
|
||||
ExprKind::Compare { .. } => "comparison",
|
||||
ExprKind::Attribute { .. } => "attribute",
|
||||
ExprKind::Call { .. } => "function call",
|
||||
ExprKind::Constant { value, .. } => match value {
|
||||
Constant::Str(_)
|
||||
| Constant::Int(_)
|
||||
| Constant::Float(_)
|
||||
| Constant::Complex { .. }
|
||||
| Constant::Bytes(_) => "literal",
|
||||
Constant::Tuple(_) => "tuple",
|
||||
Constant::Bool(b) => {
|
||||
if *b {
|
||||
"True"
|
||||
} else {
|
||||
"False"
|
||||
}
|
||||
}
|
||||
Constant::None => "None",
|
||||
Constant::Ellipsis => "ellipsis",
|
||||
},
|
||||
ExprKind::List { .. } => "list",
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
ExprKind::Dict { .. } => "dict display",
|
||||
ExprKind::Set { .. } => "set display",
|
||||
ExprKind::ListComp { .. } => "list comprehension",
|
||||
ExprKind::DictComp { .. } => "dict comprehension",
|
||||
ExprKind::SetComp { .. } => "set comprehension",
|
||||
ExprKind::GeneratorExp { .. } => "generator expression",
|
||||
ExprKind::Starred { .. } => "starred",
|
||||
ExprKind::Slice { .. } => "slice",
|
||||
ExprKind::JoinedStr { values } => {
|
||||
if values
|
||||
.iter()
|
||||
.any(|e| matches!(e.node, ExprKind::JoinedStr { .. }))
|
||||
{
|
||||
"f-string expression"
|
||||
} else {
|
||||
"literal"
|
||||
}
|
||||
}
|
||||
ExprKind::FormattedValue { .. } => "f-string expression",
|
||||
ExprKind::Name { .. } => "name",
|
||||
ExprKind::Lambda { .. } => "lambda",
|
||||
ExprKind::IfExp { .. } => "conditional expression",
|
||||
ExprKind::NamedExpr { .. } => "named expression",
|
||||
}
|
||||
}
|
||||
}
|
13
ast/src/lib.rs
Normal file
13
ast/src/lib.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
mod ast_gen;
|
||||
mod constant;
|
||||
#[cfg(feature = "fold")]
|
||||
mod fold_helpers;
|
||||
mod impls;
|
||||
mod location;
|
||||
#[cfg(feature = "unparse")]
|
||||
mod unparse;
|
||||
|
||||
pub use ast_gen::*;
|
||||
pub use location::Location;
|
||||
|
||||
pub type Suite<U = ()> = Vec<Stmt<U>>;
|
79
ast/src/location.rs
Normal file
79
ast/src/location.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
//! Datatypes to support source location information.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// A location somewhere in the sourcecode.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct Location {
|
||||
row: usize,
|
||||
column: usize,
|
||||
}
|
||||
|
||||
impl fmt::Display for Location {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "line {} column {}", self.row, self.column)
|
||||
}
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub fn visualize<'a>(
|
||||
&self,
|
||||
line: &'a str,
|
||||
desc: impl fmt::Display + 'a,
|
||||
) -> impl fmt::Display + 'a {
|
||||
struct Visualize<'a, D: fmt::Display> {
|
||||
loc: Location,
|
||||
line: &'a str,
|
||||
desc: D,
|
||||
}
|
||||
impl<D: fmt::Display> fmt::Display for Visualize<'_, D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}\n{}{arrow:>pad$}",
|
||||
self.desc,
|
||||
self.line,
|
||||
pad = self.loc.column,
|
||||
arrow = "^",
|
||||
)
|
||||
}
|
||||
}
|
||||
Visualize {
|
||||
loc: *self,
|
||||
line,
|
||||
desc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub fn new(row: usize, column: usize) -> Self {
|
||||
Location { row, column }
|
||||
}
|
||||
|
||||
pub fn row(&self) -> usize {
|
||||
self.row
|
||||
}
|
||||
|
||||
pub fn column(&self) -> usize {
|
||||
self.column
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.row = 1;
|
||||
self.column = 1;
|
||||
}
|
||||
|
||||
pub fn go_right(&mut self) {
|
||||
self.column += 1;
|
||||
}
|
||||
|
||||
pub fn go_left(&mut self) {
|
||||
self.column -= 1;
|
||||
}
|
||||
|
||||
pub fn newline(&mut self) {
|
||||
self.row += 1;
|
||||
self.column = 1;
|
||||
}
|
||||
}
|
530
ast/src/unparse.rs
Normal file
530
ast/src/unparse.rs
Normal file
|
@ -0,0 +1,530 @@
|
|||
use crate::{
|
||||
Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, ConversionFlag, Expr, ExprKind,
|
||||
Operator,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
mod precedence {
|
||||
macro_rules! precedence {
|
||||
($($op:ident,)*) => {
|
||||
precedence!(@0, $($op,)*);
|
||||
};
|
||||
(@$i:expr, $op1:ident, $($op:ident,)*) => {
|
||||
pub const $op1: u8 = $i;
|
||||
precedence!(@$i + 1, $($op,)*);
|
||||
};
|
||||
(@$i:expr,) => {};
|
||||
}
|
||||
precedence!(
|
||||
TUPLE, TEST, OR, AND, NOT, CMP, // "EXPR" =
|
||||
BOR, BXOR, BAND, SHIFT, ARITH, TERM, FACTOR, POWER, AWAIT, ATOM,
|
||||
);
|
||||
pub const EXPR: u8 = BOR;
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Unparser<'a> {
|
||||
f: fmt::Formatter<'a>,
|
||||
}
|
||||
impl<'a> Unparser<'a> {
|
||||
fn new<'b>(f: &'b mut fmt::Formatter<'a>) -> &'b mut Unparser<'a> {
|
||||
unsafe { &mut *(f as *mut fmt::Formatter<'a> as *mut Unparser<'a>) }
|
||||
}
|
||||
|
||||
fn p(&mut self, s: &str) -> fmt::Result {
|
||||
self.f.write_str(s)
|
||||
}
|
||||
fn p_if(&mut self, cond: bool, s: &str) -> fmt::Result {
|
||||
if cond {
|
||||
self.f.write_str(s)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn p_delim(&mut self, first: &mut bool, s: &str) -> fmt::Result {
|
||||
self.p_if(!std::mem::take(first), s)
|
||||
}
|
||||
fn write_fmt(&mut self, f: fmt::Arguments<'_>) -> fmt::Result {
|
||||
self.f.write_fmt(f)
|
||||
}
|
||||
|
||||
fn unparse_expr<U>(&mut self, ast: &Expr<U>, level: u8) -> fmt::Result {
|
||||
macro_rules! opprec {
|
||||
($opty:ident, $x:expr, $enu:path, $($var:ident($op:literal, $prec:ident)),*$(,)?) => {
|
||||
match $x {
|
||||
$(<$enu>::$var => (opprec!(@space $opty, $op), precedence::$prec),)*
|
||||
}
|
||||
};
|
||||
(@space bin, $op:literal) => {
|
||||
concat!(" ", $op, " ")
|
||||
};
|
||||
(@space un, $op:literal) => {
|
||||
$op
|
||||
};
|
||||
}
|
||||
macro_rules! group_if {
|
||||
($lvl:expr, $body:block) => {{
|
||||
let group = level > $lvl;
|
||||
self.p_if(group, "(")?;
|
||||
let ret = $body;
|
||||
self.p_if(group, ")")?;
|
||||
ret
|
||||
}};
|
||||
}
|
||||
match &ast.node {
|
||||
ExprKind::BoolOp { op, values } => {
|
||||
let (op, prec) = opprec!(bin, op, Boolop, And("and", AND), Or("or", OR));
|
||||
group_if!(prec, {
|
||||
let mut first = true;
|
||||
for val in values {
|
||||
self.p_delim(&mut first, op)?;
|
||||
self.unparse_expr(val, prec + 1)?;
|
||||
}
|
||||
})
|
||||
}
|
||||
ExprKind::NamedExpr { target, value } => {
|
||||
group_if!(precedence::TUPLE, {
|
||||
self.unparse_expr(target, precedence::ATOM)?;
|
||||
self.p(" := ")?;
|
||||
self.unparse_expr(value, precedence::ATOM)?;
|
||||
})
|
||||
}
|
||||
ExprKind::BinOp { left, op, right } => {
|
||||
let rassoc = matches!(op, Operator::Pow);
|
||||
let (op, prec) = opprec!(
|
||||
bin,
|
||||
op,
|
||||
Operator,
|
||||
Add("+", ARITH),
|
||||
Sub("-", ARITH),
|
||||
Mult("*", TERM),
|
||||
MatMult("@", TERM),
|
||||
Div("/", TERM),
|
||||
Mod("%", TERM),
|
||||
Pow("**", POWER),
|
||||
LShift("<<", SHIFT),
|
||||
RShift(">>", SHIFT),
|
||||
BitOr("|", BOR),
|
||||
BitXor("^", BXOR),
|
||||
BitAnd("&", BAND),
|
||||
FloorDiv("//", TERM),
|
||||
);
|
||||
group_if!(prec, {
|
||||
self.unparse_expr(left, prec + rassoc as u8)?;
|
||||
self.p(op)?;
|
||||
self.unparse_expr(right, prec + !rassoc as u8)?;
|
||||
})
|
||||
}
|
||||
ExprKind::UnaryOp { op, operand } => {
|
||||
let (op, prec) = opprec!(
|
||||
un,
|
||||
op,
|
||||
crate::Unaryop,
|
||||
Invert("~", FACTOR),
|
||||
Not("not ", NOT),
|
||||
UAdd("+", FACTOR),
|
||||
USub("-", FACTOR)
|
||||
);
|
||||
group_if!(prec, {
|
||||
self.p(op)?;
|
||||
self.unparse_expr(operand, prec)?;
|
||||
})
|
||||
}
|
||||
ExprKind::Lambda { args, body } => {
|
||||
group_if!(precedence::TEST, {
|
||||
let npos = args.args.len() + args.posonlyargs.len();
|
||||
self.p(if npos > 0 { "lambda " } else { "lambda" })?;
|
||||
self.unparse_args(args)?;
|
||||
write!(self, ": {}", **body)?;
|
||||
})
|
||||
}
|
||||
ExprKind::IfExp { test, body, orelse } => {
|
||||
group_if!(precedence::TEST, {
|
||||
self.unparse_expr(body, precedence::TEST + 1)?;
|
||||
self.p(" if ")?;
|
||||
self.unparse_expr(test, precedence::TEST + 1)?;
|
||||
self.p(" else ")?;
|
||||
self.unparse_expr(orelse, precedence::TEST)?;
|
||||
})
|
||||
}
|
||||
ExprKind::Dict { keys, values } => {
|
||||
self.p("{")?;
|
||||
let mut first = true;
|
||||
let (packed, unpacked) = values.split_at(keys.len());
|
||||
for (k, v) in keys.iter().zip(packed) {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
write!(self, "{}: {}", *k, *v)?;
|
||||
}
|
||||
for d in unpacked {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
write!(self, "**{}", *d)?;
|
||||
}
|
||||
self.p("}")?;
|
||||
}
|
||||
ExprKind::Set { elts } => {
|
||||
self.p("{")?;
|
||||
let mut first = true;
|
||||
for v in elts {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_expr(v, precedence::TEST)?;
|
||||
}
|
||||
self.p("}")?;
|
||||
}
|
||||
ExprKind::ListComp { elt, generators } => {
|
||||
self.p("[")?;
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
self.unparse_comp(generators)?;
|
||||
self.p("]")?;
|
||||
}
|
||||
ExprKind::SetComp { elt, generators } => {
|
||||
self.p("{")?;
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
self.unparse_comp(generators)?;
|
||||
self.p("}")?;
|
||||
}
|
||||
ExprKind::DictComp {
|
||||
key,
|
||||
value,
|
||||
generators,
|
||||
} => {
|
||||
self.p("{")?;
|
||||
self.unparse_expr(key, precedence::TEST)?;
|
||||
self.p(": ")?;
|
||||
self.unparse_expr(value, precedence::TEST)?;
|
||||
self.unparse_comp(generators)?;
|
||||
self.p("}")?;
|
||||
}
|
||||
ExprKind::GeneratorExp { elt, generators } => {
|
||||
self.p("(")?;
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
self.unparse_comp(generators)?;
|
||||
self.p(")")?;
|
||||
}
|
||||
ExprKind::Await { value } => {
|
||||
group_if!(precedence::AWAIT, {
|
||||
self.p("await ")?;
|
||||
self.unparse_expr(value, precedence::ATOM)?;
|
||||
})
|
||||
}
|
||||
ExprKind::Yield { value } => {
|
||||
if let Some(value) = value {
|
||||
write!(self, "(yield {})", **value)?;
|
||||
} else {
|
||||
self.p("(yield)")?;
|
||||
}
|
||||
}
|
||||
ExprKind::YieldFrom { value } => {
|
||||
write!(self, "(yield from {})", **value)?;
|
||||
}
|
||||
ExprKind::Compare {
|
||||
left,
|
||||
ops,
|
||||
comparators,
|
||||
} => {
|
||||
group_if!(precedence::CMP, {
|
||||
let new_lvl = precedence::CMP + 1;
|
||||
self.unparse_expr(left, new_lvl)?;
|
||||
for (op, cmp) in ops.iter().zip(comparators) {
|
||||
let op = match op {
|
||||
Cmpop::Eq => " == ",
|
||||
Cmpop::NotEq => " != ",
|
||||
Cmpop::Lt => " < ",
|
||||
Cmpop::LtE => " <= ",
|
||||
Cmpop::Gt => " > ",
|
||||
Cmpop::GtE => " >= ",
|
||||
Cmpop::Is => " is ",
|
||||
Cmpop::IsNot => " is not ",
|
||||
Cmpop::In => " in ",
|
||||
Cmpop::NotIn => " not in ",
|
||||
};
|
||||
self.p(op)?;
|
||||
self.unparse_expr(cmp, new_lvl)?;
|
||||
}
|
||||
})
|
||||
}
|
||||
ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
} => {
|
||||
self.unparse_expr(func, precedence::ATOM)?;
|
||||
self.p("(")?;
|
||||
if let (
|
||||
[Expr {
|
||||
node: ExprKind::GeneratorExp { elt, generators },
|
||||
..
|
||||
}],
|
||||
[],
|
||||
) = (&**args, &**keywords)
|
||||
{
|
||||
// make sure a single genexp doesn't get double parens
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
self.unparse_comp(generators)?;
|
||||
} else {
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_expr(arg, precedence::TEST)?;
|
||||
}
|
||||
for kw in keywords {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
if let Some(arg) = &kw.node.arg {
|
||||
self.p(arg)?;
|
||||
self.p("=")?;
|
||||
} else {
|
||||
self.p("**")?;
|
||||
}
|
||||
self.unparse_expr(&kw.node.value, precedence::TEST)?;
|
||||
}
|
||||
}
|
||||
self.p(")")?;
|
||||
}
|
||||
ExprKind::FormattedValue {
|
||||
value,
|
||||
conversion,
|
||||
format_spec,
|
||||
} => self.unparse_formatted(value, *conversion, format_spec.as_deref())?,
|
||||
ExprKind::JoinedStr { values } => self.unparse_joinedstr(values, false)?,
|
||||
ExprKind::Constant { value, kind } => {
|
||||
if let Some(kind) = kind {
|
||||
self.p(kind)?;
|
||||
}
|
||||
assert_eq!(f64::MAX_10_EXP, 308);
|
||||
let inf_str = "1e309";
|
||||
match value {
|
||||
Constant::Float(f) if f.is_infinite() => self.p(inf_str)?,
|
||||
Constant::Complex { real, imag }
|
||||
if real.is_infinite() || imag.is_infinite() =>
|
||||
{
|
||||
self.p(&value.to_string().replace("inf", inf_str))?
|
||||
}
|
||||
_ => fmt::Display::fmt(value, &mut self.f)?,
|
||||
}
|
||||
}
|
||||
ExprKind::Attribute { value, attr, .. } => {
|
||||
self.unparse_expr(value, precedence::ATOM)?;
|
||||
let period = if let ExprKind::Constant {
|
||||
value: Constant::Int(_),
|
||||
..
|
||||
} = &value.node
|
||||
{
|
||||
" ."
|
||||
} else {
|
||||
"."
|
||||
};
|
||||
self.p(period)?;
|
||||
self.p(attr)?;
|
||||
}
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
self.unparse_expr(value, precedence::ATOM)?;
|
||||
let mut lvl = precedence::TUPLE;
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
if elts
|
||||
.iter()
|
||||
.any(|expr| matches!(expr.node, ExprKind::Starred { .. }))
|
||||
{
|
||||
lvl += 1
|
||||
}
|
||||
}
|
||||
self.p("[")?;
|
||||
self.unparse_expr(slice, lvl)?;
|
||||
self.p("]")?;
|
||||
}
|
||||
ExprKind::Starred { value, .. } => {
|
||||
self.p("*")?;
|
||||
self.unparse_expr(value, precedence::EXPR)?;
|
||||
}
|
||||
ExprKind::Name { id, .. } => self.p(id)?,
|
||||
ExprKind::List { elts, .. } => {
|
||||
self.p("[")?;
|
||||
let mut first = true;
|
||||
for elt in elts {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
}
|
||||
self.p("]")?;
|
||||
}
|
||||
ExprKind::Tuple { elts, .. } => {
|
||||
if elts.is_empty() {
|
||||
self.p("()")?;
|
||||
} else {
|
||||
group_if!(precedence::TUPLE, {
|
||||
let mut first = true;
|
||||
for elt in elts {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_expr(elt, precedence::TEST)?;
|
||||
}
|
||||
self.p_if(elts.len() == 1, ",")?;
|
||||
})
|
||||
}
|
||||
}
|
||||
ExprKind::Slice { lower, upper, step } => {
|
||||
if let Some(lower) = lower {
|
||||
self.unparse_expr(lower, precedence::TEST)?;
|
||||
}
|
||||
self.p(":")?;
|
||||
if let Some(upper) = upper {
|
||||
self.unparse_expr(upper, precedence::TEST)?;
|
||||
}
|
||||
if let Some(step) = step {
|
||||
self.p(":")?;
|
||||
self.unparse_expr(step, precedence::TEST)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unparse_args<U>(&mut self, args: &Arguments<U>) -> fmt::Result {
|
||||
let mut first = true;
|
||||
let defaults_start = args.posonlyargs.len() + args.args.len() - args.defaults.len();
|
||||
for (i, arg) in args.posonlyargs.iter().chain(&args.args).enumerate() {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_arg(arg)?;
|
||||
if let Some(i) = i.checked_sub(defaults_start) {
|
||||
write!(self, "={}", &args.defaults[i])?;
|
||||
}
|
||||
self.p_if(i + 1 == args.posonlyargs.len(), ", /")?;
|
||||
}
|
||||
if args.vararg.is_some() || !args.kwonlyargs.is_empty() {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.p("*")?;
|
||||
}
|
||||
if let Some(vararg) = &args.vararg {
|
||||
self.unparse_arg(vararg)?;
|
||||
}
|
||||
let defaults_start = args.kwonlyargs.len() - args.kw_defaults.len();
|
||||
for (i, kwarg) in args.kwonlyargs.iter().enumerate() {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.unparse_arg(kwarg)?;
|
||||
if let Some(default) = i
|
||||
.checked_sub(defaults_start)
|
||||
.and_then(|i| args.kw_defaults.get(i))
|
||||
{
|
||||
write!(self, "={}", default)?;
|
||||
}
|
||||
}
|
||||
if let Some(kwarg) = &args.kwarg {
|
||||
self.p_delim(&mut first, ", ")?;
|
||||
self.p("**")?;
|
||||
self.unparse_arg(kwarg)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn unparse_arg<U>(&mut self, arg: &Arg<U>) -> fmt::Result {
|
||||
self.p(&arg.node.arg)?;
|
||||
if let Some(ann) = &arg.node.annotation {
|
||||
write!(self, ": {}", **ann)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unparse_comp<U>(&mut self, generators: &[Comprehension<U>]) -> fmt::Result {
|
||||
for comp in generators {
|
||||
self.p(if comp.is_async > 0 {
|
||||
" async for "
|
||||
} else {
|
||||
" for "
|
||||
})?;
|
||||
self.unparse_expr(&comp.target, precedence::TUPLE)?;
|
||||
self.p(" in ")?;
|
||||
self.unparse_expr(&comp.iter, precedence::TEST + 1)?;
|
||||
for cond in &comp.ifs {
|
||||
self.p(" if ")?;
|
||||
self.unparse_expr(cond, precedence::TEST + 1)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unparse_fstring_body<U>(&mut self, values: &[Expr<U>], is_spec: bool) -> fmt::Result {
|
||||
for value in values {
|
||||
self.unparse_fstring_elem(value, is_spec)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unparse_formatted<U>(
|
||||
&mut self,
|
||||
val: &Expr<U>,
|
||||
conversion: usize,
|
||||
spec: Option<&Expr<U>>,
|
||||
) -> fmt::Result {
|
||||
let buffered = to_string_fmt(|f| Unparser::new(f).unparse_expr(val, precedence::TEST + 1));
|
||||
let brace = if buffered.starts_with('{') {
|
||||
// put a space to avoid escaping the bracket
|
||||
"{ "
|
||||
} else {
|
||||
"{"
|
||||
};
|
||||
self.p(brace)?;
|
||||
self.p(&buffered)?;
|
||||
drop(buffered);
|
||||
|
||||
if conversion != ConversionFlag::None as usize {
|
||||
self.p("!")?;
|
||||
let buf = &[conversion as u8];
|
||||
let c = std::str::from_utf8(buf).unwrap();
|
||||
self.p(c)?;
|
||||
}
|
||||
|
||||
if let Some(spec) = spec {
|
||||
self.p(":")?;
|
||||
self.unparse_fstring_elem(spec, true)?;
|
||||
}
|
||||
|
||||
self.p("}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unparse_fstring_elem<U>(&mut self, expr: &Expr<U>, is_spec: bool) -> fmt::Result {
|
||||
match &expr.node {
|
||||
ExprKind::Constant { value, .. } => {
|
||||
if let Constant::Str(s) = value {
|
||||
self.unparse_fstring_str(s)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ExprKind::JoinedStr { values } => self.unparse_joinedstr(values, is_spec),
|
||||
ExprKind::FormattedValue {
|
||||
value,
|
||||
conversion,
|
||||
format_spec,
|
||||
} => self.unparse_formatted(value, *conversion, format_spec.as_deref()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn unparse_fstring_str(&mut self, s: &str) -> fmt::Result {
|
||||
let s = s.replace('{', "{{").replace('}', "}}");
|
||||
self.p(&s)
|
||||
}
|
||||
|
||||
fn unparse_joinedstr<U>(&mut self, values: &[Expr<U>], is_spec: bool) -> fmt::Result {
|
||||
if is_spec {
|
||||
self.unparse_fstring_body(values, is_spec)
|
||||
} else {
|
||||
self.p("f")?;
|
||||
let body = to_string_fmt(|f| Unparser::new(f).unparse_fstring_body(values, is_spec));
|
||||
fmt::Display::fmt(&rustpython_common::str::repr(&body), &mut self.f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<U> fmt::Display for Expr<U> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Unparser::new(f).unparse_expr(self, precedence::TEST)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string_fmt(f: impl FnOnce(&mut fmt::Formatter) -> fmt::Result) -> String {
|
||||
use std::cell::Cell;
|
||||
struct Fmt<F>(Cell<Option<F>>);
|
||||
impl<F: FnOnce(&mut fmt::Formatter) -> fmt::Result> fmt::Display for Fmt<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.take().unwrap()(f)
|
||||
}
|
||||
}
|
||||
Fmt(Cell::new(Some(f))).to_string()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue