RustPython-Parser/ast/src/unparse.rs
Jeong YunWon a3d9d8cb14 numerous refactoring
- Split parser core and compiler core. Fix #14
- AST int type to `u32`
- Updated asdl_rs.py and update_asdl.sh fix #6
- Use `ruff_python_ast::SourceLocation` for Python source location. Deleted our own Location.
- Renamed ast::Located to ast::Attributed to distinguish terms for TextSize and SourceLocation
- `ast::<Node>`s for TextSize located ast. `ast::located::<Node>` for Python source located ast.
- And also strictly renaming `located` to refer only python location related interfaces.
- `SourceLocator` to convert locations.
- New `source-code` features of to disable python locations when unnecessary.
- Also including fully merging https://github.com/astral-sh/RustPython/pull/4 closes #9
2023-05-10 14:35:38 +09:00

538 lines
20 KiB
Rust

use crate::ConversionFlag;
use crate::{Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, 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! op_prec {
($op_ty:ident, $x:expr, $enu:path, $($var:ident($op:literal, $prec:ident)),*$(,)?) => {
match $x {
$(<$enu>::$var => (op_prec!(@space $op_ty, $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(crate::ExprBoolOp { op, values }) => {
let (op, prec) = op_prec!(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(crate::ExprNamedExpr { target, value }) => {
group_if!(precedence::TUPLE, {
self.unparse_expr(target, precedence::ATOM)?;
self.p(" := ")?;
self.unparse_expr(value, precedence::ATOM)?;
})
}
ExprKind::BinOp(crate::ExprBinOp { left, op, right }) => {
let right_associative = matches!(op, Operator::Pow);
let (op, prec) = op_prec!(
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 + right_associative as u8)?;
self.p(op)?;
self.unparse_expr(right, prec + !right_associative as u8)?;
})
}
ExprKind::UnaryOp(crate::ExprUnaryOp { op, operand }) => {
let (op, prec) = op_prec!(
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(crate::ExprLambda { args, body }) => {
group_if!(precedence::TEST, {
let pos = args.args.len() + args.posonlyargs.len();
self.p(if pos > 0 { "lambda " } else { "lambda" })?;
self.unparse_args(args)?;
write!(self, ": {}", **body)?;
})
}
ExprKind::IfExp(crate::ExprIfExp { 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(crate::ExprDict { 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, ", ")?;
if let Some(k) = k {
write!(self, "{}: {}", *k, *v)?;
} else {
write!(self, "**{}", *v)?;
}
}
for d in unpacked {
self.p_delim(&mut first, ", ")?;
write!(self, "**{}", *d)?;
}
self.p("}")?;
}
ExprKind::Set(crate::ExprSet { 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(crate::ExprListComp { elt, generators }) => {
self.p("[")?;
self.unparse_expr(elt, precedence::TEST)?;
self.unparse_comp(generators)?;
self.p("]")?;
}
ExprKind::SetComp(crate::ExprSetComp { elt, generators }) => {
self.p("{")?;
self.unparse_expr(elt, precedence::TEST)?;
self.unparse_comp(generators)?;
self.p("}")?;
}
ExprKind::DictComp(crate::ExprDictComp {
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(crate::ExprGeneratorExp { elt, generators }) => {
self.p("(")?;
self.unparse_expr(elt, precedence::TEST)?;
self.unparse_comp(generators)?;
self.p(")")?;
}
ExprKind::Await(crate::ExprAwait { value }) => {
group_if!(precedence::AWAIT, {
self.p("await ")?;
self.unparse_expr(value, precedence::ATOM)?;
})
}
ExprKind::Yield(crate::ExprYield { value }) => {
if let Some(value) = value {
write!(self, "(yield {})", **value)?;
} else {
self.p("(yield)")?;
}
}
ExprKind::YieldFrom(crate::ExprYieldFrom { value }) => {
write!(self, "(yield from {})", **value)?;
}
ExprKind::Compare(crate::ExprCompare {
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(crate::ExprCall {
func,
args,
keywords,
}) => {
self.unparse_expr(func, precedence::ATOM)?;
self.p("(")?;
if let (
[Expr {
node: ExprKind::GeneratorExp(crate::ExprGeneratorExp { elt, generators }),
..
}],
[],
) = (&**args, &**keywords)
{
// make sure a single genexpr 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(crate::ExprFormattedValue {
value,
conversion,
format_spec,
}) => self.unparse_formatted(value, *conversion, format_spec.as_deref())?,
ExprKind::JoinedStr(crate::ExprJoinedStr { values }) => {
self.unparse_joined_str(values, false)?
}
ExprKind::Constant(crate::ExprConstant { 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(crate::ExprAttribute { value, attr, .. }) => {
self.unparse_expr(value, precedence::ATOM)?;
let period = if let ExprKind::Constant(crate::ExprConstant {
value: Constant::Int(_),
..
}) = &value.node
{
" ."
} else {
"."
};
self.p(period)?;
self.p(attr)?;
}
ExprKind::Subscript(crate::ExprSubscript { value, slice, .. }) => {
self.unparse_expr(value, precedence::ATOM)?;
let mut lvl = precedence::TUPLE;
if let ExprKind::Tuple(crate::ExprTuple { 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(crate::ExprStarred { value, .. }) => {
self.p("*")?;
self.unparse_expr(value, precedence::EXPR)?;
}
ExprKind::Name(crate::ExprName { id, .. }) => self.p(id)?,
ExprKind::List(crate::ExprList { 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(crate::ExprTuple { 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(crate::ExprSlice { 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: u32,
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 u32 {
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(crate::ExprConstant { value, .. }) => {
if let Constant::Str(s) = value {
self.unparse_fstring_str(s)
} else {
unreachable!()
}
}
ExprKind::JoinedStr(crate::ExprJoinedStr { values }) => {
self.unparse_joined_str(values, is_spec)
}
ExprKind::FormattedValue(crate::ExprFormattedValue {
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_joined_str<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));
rustpython_literal::escape::UnicodeEscape::new_repr(&body)
.str_repr()
.write(&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()
}