| use crate::algorithm::{BreakToken, Printer}; |
| use crate::attr; |
| use crate::iter::IterDelimited; |
| use crate::stmt; |
| use crate::INDENT; |
| use proc_macro2::TokenStream; |
| use syn::punctuated::Punctuated; |
| use syn::{ |
| token, Arm, Attribute, BinOp, Block, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, |
| ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, |
| ExprContinue, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop, |
| ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, |
| ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, |
| ExprUnsafe, ExprWhile, ExprYield, FieldValue, GenericMethodArgument, Index, Label, Member, |
| MethodTurbofish, PathArguments, QSelf, RangeLimits, ReturnType, Stmt, Token, UnOp, |
| }; |
| |
| impl Printer { |
| pub fn expr(&mut self, expr: &Expr) { |
| match expr { |
| Expr::Array(expr) => self.expr_array(expr), |
| Expr::Assign(expr) => self.expr_assign(expr), |
| Expr::AssignOp(expr) => self.expr_assign_op(expr), |
| Expr::Async(expr) => self.expr_async(expr), |
| Expr::Await(expr) => self.expr_await(expr, false), |
| Expr::Binary(expr) => self.expr_binary(expr), |
| Expr::Block(expr) => self.expr_block(expr), |
| Expr::Box(expr) => self.expr_box(expr), |
| Expr::Break(expr) => self.expr_break(expr), |
| Expr::Call(expr) => self.expr_call(expr, false), |
| Expr::Cast(expr) => self.expr_cast(expr), |
| Expr::Closure(expr) => self.expr_closure(expr), |
| Expr::Continue(expr) => self.expr_continue(expr), |
| Expr::Field(expr) => self.expr_field(expr, false), |
| Expr::ForLoop(expr) => self.expr_for_loop(expr), |
| Expr::Group(expr) => self.expr_group(expr), |
| Expr::If(expr) => self.expr_if(expr), |
| Expr::Index(expr) => self.expr_index(expr, false), |
| Expr::Let(expr) => self.expr_let(expr), |
| Expr::Lit(expr) => self.expr_lit(expr), |
| Expr::Loop(expr) => self.expr_loop(expr), |
| Expr::Macro(expr) => self.expr_macro(expr), |
| Expr::Match(expr) => self.expr_match(expr), |
| Expr::MethodCall(expr) => self.expr_method_call(expr, false), |
| Expr::Paren(expr) => self.expr_paren(expr), |
| Expr::Path(expr) => self.expr_path(expr), |
| Expr::Range(expr) => self.expr_range(expr), |
| Expr::Reference(expr) => self.expr_reference(expr), |
| Expr::Repeat(expr) => self.expr_repeat(expr), |
| Expr::Return(expr) => self.expr_return(expr), |
| Expr::Struct(expr) => self.expr_struct(expr), |
| Expr::Try(expr) => self.expr_try(expr, false), |
| Expr::TryBlock(expr) => self.expr_try_block(expr), |
| Expr::Tuple(expr) => self.expr_tuple(expr), |
| Expr::Type(expr) => self.expr_type(expr), |
| Expr::Unary(expr) => self.expr_unary(expr), |
| Expr::Unsafe(expr) => self.expr_unsafe(expr), |
| Expr::Verbatim(expr) => self.expr_verbatim(expr), |
| Expr::While(expr) => self.expr_while(expr), |
| Expr::Yield(expr) => self.expr_yield(expr), |
| #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
| _ => unimplemented!("unknown Expr"), |
| } |
| } |
| |
| pub fn expr_beginning_of_line(&mut self, expr: &Expr, beginning_of_line: bool) { |
| match expr { |
| Expr::Await(expr) => self.expr_await(expr, beginning_of_line), |
| Expr::Field(expr) => self.expr_field(expr, beginning_of_line), |
| Expr::Index(expr) => self.expr_index(expr, beginning_of_line), |
| Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line), |
| Expr::Try(expr) => self.expr_try(expr, beginning_of_line), |
| _ => self.expr(expr), |
| } |
| } |
| |
| fn subexpr(&mut self, expr: &Expr, beginning_of_line: bool) { |
| match expr { |
| Expr::Await(expr) => self.subexpr_await(expr, beginning_of_line), |
| Expr::Call(expr) => self.subexpr_call(expr), |
| Expr::Field(expr) => self.subexpr_field(expr, beginning_of_line), |
| Expr::Index(expr) => self.subexpr_index(expr, beginning_of_line), |
| Expr::MethodCall(expr) => self.subexpr_method_call(expr, beginning_of_line, false), |
| Expr::Try(expr) => self.subexpr_try(expr, beginning_of_line), |
| _ => { |
| self.cbox(-INDENT); |
| self.expr(expr); |
| self.end(); |
| } |
| } |
| } |
| |
| // If the given expression is a bare `ExprStruct`, wraps it in parenthesis |
| // before appending it to `TokenStream`. |
| fn wrap_exterior_struct(&mut self, expr: &Expr) { |
| let needs_paren = contains_exterior_struct_lit(expr); |
| if needs_paren { |
| self.word("("); |
| } |
| self.cbox(0); |
| self.expr(expr); |
| if needs_paren { |
| self.word(")"); |
| } |
| if needs_newline_if_wrap(expr) { |
| self.space(); |
| } else { |
| self.nbsp(); |
| } |
| self.end(); |
| } |
| |
| fn expr_array(&mut self, expr: &ExprArray) { |
| self.outer_attrs(&expr.attrs); |
| self.word("["); |
| self.cbox(INDENT); |
| self.zerobreak(); |
| for element in expr.elems.iter().delimited() { |
| self.expr(&element); |
| self.trailing_comma(element.is_last); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("]"); |
| } |
| |
| fn expr_assign(&mut self, expr: &ExprAssign) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(0); |
| self.expr(&expr.left); |
| self.word(" = "); |
| self.expr(&expr.right); |
| self.end(); |
| } |
| |
| fn expr_assign_op(&mut self, expr: &ExprAssignOp) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(INDENT); |
| self.ibox(-INDENT); |
| self.expr(&expr.left); |
| self.end(); |
| self.space(); |
| self.binary_operator(&expr.op); |
| self.nbsp(); |
| self.expr(&expr.right); |
| self.end(); |
| } |
| |
| fn expr_async(&mut self, expr: &ExprAsync) { |
| self.outer_attrs(&expr.attrs); |
| self.word("async "); |
| if expr.capture.is_some() { |
| self.word("move "); |
| } |
| self.cbox(INDENT); |
| self.small_block(&expr.block, &expr.attrs); |
| self.end(); |
| } |
| |
| fn expr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| self.subexpr_await(expr, beginning_of_line); |
| self.end(); |
| } |
| |
| fn subexpr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) { |
| self.subexpr(&expr.base, beginning_of_line); |
| self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); |
| self.word(".await"); |
| } |
| |
| fn expr_binary(&mut self, expr: &ExprBinary) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(INDENT); |
| self.ibox(-INDENT); |
| self.expr(&expr.left); |
| self.end(); |
| self.space(); |
| self.binary_operator(&expr.op); |
| self.nbsp(); |
| self.expr(&expr.right); |
| self.end(); |
| } |
| |
| pub fn expr_block(&mut self, expr: &ExprBlock) { |
| self.outer_attrs(&expr.attrs); |
| if let Some(label) = &expr.label { |
| self.label(label); |
| } |
| self.cbox(INDENT); |
| self.small_block(&expr.block, &expr.attrs); |
| self.end(); |
| } |
| |
| fn expr_box(&mut self, expr: &ExprBox) { |
| self.outer_attrs(&expr.attrs); |
| self.word("box "); |
| self.expr(&expr.expr); |
| } |
| |
| fn expr_break(&mut self, expr: &ExprBreak) { |
| self.outer_attrs(&expr.attrs); |
| self.word("break"); |
| if let Some(lifetime) = &expr.label { |
| self.nbsp(); |
| self.lifetime(lifetime); |
| } |
| if let Some(value) = &expr.expr { |
| self.nbsp(); |
| self.expr(value); |
| } |
| } |
| |
| fn expr_call(&mut self, expr: &ExprCall, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.expr_beginning_of_line(&expr.func, beginning_of_line); |
| self.word("("); |
| self.call_args(&expr.args); |
| self.word(")"); |
| } |
| |
| fn subexpr_call(&mut self, expr: &ExprCall) { |
| self.subexpr(&expr.func, false); |
| self.word("("); |
| self.call_args(&expr.args); |
| self.word(")"); |
| } |
| |
| fn expr_cast(&mut self, expr: &ExprCast) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(INDENT); |
| self.ibox(-INDENT); |
| self.expr(&expr.expr); |
| self.end(); |
| self.space(); |
| self.word("as "); |
| self.ty(&expr.ty); |
| self.end(); |
| } |
| |
| fn expr_closure(&mut self, expr: &ExprClosure) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(0); |
| if expr.asyncness.is_some() { |
| self.word("async "); |
| } |
| if expr.movability.is_some() { |
| self.word("static "); |
| } |
| if expr.capture.is_some() { |
| self.word("move "); |
| } |
| self.cbox(INDENT); |
| self.word("|"); |
| for pat in expr.inputs.iter().delimited() { |
| if pat.is_first { |
| self.zerobreak(); |
| } |
| self.pat(&pat); |
| if !pat.is_last { |
| self.word(","); |
| self.space(); |
| } |
| } |
| match &expr.output { |
| ReturnType::Default => { |
| self.word("|"); |
| self.space(); |
| self.offset(-INDENT); |
| self.end(); |
| self.neverbreak(); |
| let wrap_in_brace = match &*expr.body { |
| Expr::Match(ExprMatch { attrs, .. }) | Expr::Call(ExprCall { attrs, .. }) => { |
| attr::has_outer(attrs) |
| } |
| body => !is_blocklike(body), |
| }; |
| if wrap_in_brace { |
| self.cbox(INDENT); |
| self.scan_break(BreakToken { |
| pre_break: Some('{'), |
| ..BreakToken::default() |
| }); |
| self.expr(&expr.body); |
| self.scan_break(BreakToken { |
| offset: -INDENT, |
| pre_break: stmt::add_semi(&expr.body).then(|| ';'), |
| post_break: Some('}'), |
| ..BreakToken::default() |
| }); |
| self.end(); |
| } else { |
| self.expr(&expr.body); |
| } |
| } |
| ReturnType::Type(_arrow, ty) => { |
| if !expr.inputs.is_empty() { |
| self.trailing_comma(true); |
| self.offset(-INDENT); |
| } |
| self.word("|"); |
| self.end(); |
| self.word(" -> "); |
| self.ty(ty); |
| self.nbsp(); |
| self.neverbreak(); |
| self.expr(&expr.body); |
| } |
| } |
| self.end(); |
| } |
| |
| fn expr_continue(&mut self, expr: &ExprContinue) { |
| self.outer_attrs(&expr.attrs); |
| self.word("continue"); |
| if let Some(lifetime) = &expr.label { |
| self.nbsp(); |
| self.lifetime(lifetime); |
| } |
| } |
| |
| fn expr_field(&mut self, expr: &ExprField, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| self.subexpr_field(expr, beginning_of_line); |
| self.end(); |
| } |
| |
| fn subexpr_field(&mut self, expr: &ExprField, beginning_of_line: bool) { |
| self.subexpr(&expr.base, beginning_of_line); |
| self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); |
| self.word("."); |
| self.member(&expr.member); |
| } |
| |
| fn expr_for_loop(&mut self, expr: &ExprForLoop) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(0); |
| if let Some(label) = &expr.label { |
| self.label(label); |
| } |
| self.word("for "); |
| self.pat(&expr.pat); |
| self.word(" in "); |
| self.neverbreak(); |
| self.wrap_exterior_struct(&expr.expr); |
| self.word("{"); |
| self.neverbreak(); |
| self.cbox(INDENT); |
| self.hardbreak_if_nonempty(); |
| self.inner_attrs(&expr.attrs); |
| for stmt in &expr.body.stmts { |
| self.stmt(stmt); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| self.end(); |
| } |
| |
| fn expr_group(&mut self, expr: &ExprGroup) { |
| self.outer_attrs(&expr.attrs); |
| self.expr(&expr.expr); |
| } |
| |
| fn expr_if(&mut self, expr: &ExprIf) { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| self.word("if "); |
| self.cbox(-INDENT); |
| self.wrap_exterior_struct(&expr.cond); |
| self.end(); |
| if let Some((_else_token, else_branch)) = &expr.else_branch { |
| let mut else_branch = &**else_branch; |
| self.small_block(&expr.then_branch, &[]); |
| loop { |
| self.word(" else "); |
| match else_branch { |
| Expr::If(expr) => { |
| self.word("if "); |
| self.cbox(-INDENT); |
| self.wrap_exterior_struct(&expr.cond); |
| self.end(); |
| self.small_block(&expr.then_branch, &[]); |
| if let Some((_else_token, next)) = &expr.else_branch { |
| else_branch = next; |
| continue; |
| } |
| } |
| Expr::Block(expr) => { |
| self.small_block(&expr.block, &[]); |
| } |
| // If not one of the valid expressions to exist in an else |
| // clause, wrap in a block. |
| other => { |
| self.word("{"); |
| self.space(); |
| self.ibox(INDENT); |
| self.expr(other); |
| self.end(); |
| self.space(); |
| self.offset(-INDENT); |
| self.word("}"); |
| } |
| } |
| break; |
| } |
| } else if expr.then_branch.stmts.is_empty() { |
| self.word("{}"); |
| } else { |
| self.word("{"); |
| self.hardbreak(); |
| for stmt in &expr.then_branch.stmts { |
| self.stmt(stmt); |
| } |
| self.offset(-INDENT); |
| self.word("}"); |
| } |
| self.end(); |
| } |
| |
| fn expr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.expr_beginning_of_line(&expr.expr, beginning_of_line); |
| self.word("["); |
| self.expr(&expr.index); |
| self.word("]"); |
| } |
| |
| fn subexpr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { |
| self.subexpr(&expr.expr, beginning_of_line); |
| self.word("["); |
| self.expr(&expr.index); |
| self.word("]"); |
| } |
| |
| fn expr_let(&mut self, expr: &ExprLet) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(INDENT); |
| self.word("let "); |
| self.ibox(-INDENT); |
| self.pat(&expr.pat); |
| self.end(); |
| self.space(); |
| self.word("= "); |
| let needs_paren = contains_exterior_struct_lit(&expr.expr); |
| if needs_paren { |
| self.word("("); |
| } |
| self.expr(&expr.expr); |
| if needs_paren { |
| self.word(")"); |
| } |
| self.end(); |
| } |
| |
| pub fn expr_lit(&mut self, expr: &ExprLit) { |
| self.outer_attrs(&expr.attrs); |
| self.lit(&expr.lit); |
| } |
| |
| fn expr_loop(&mut self, expr: &ExprLoop) { |
| self.outer_attrs(&expr.attrs); |
| if let Some(label) = &expr.label { |
| self.label(label); |
| } |
| self.word("loop {"); |
| self.cbox(INDENT); |
| self.hardbreak_if_nonempty(); |
| self.inner_attrs(&expr.attrs); |
| for stmt in &expr.body.stmts { |
| self.stmt(stmt); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| } |
| |
| fn expr_macro(&mut self, expr: &ExprMacro) { |
| self.outer_attrs(&expr.attrs); |
| self.mac(&expr.mac, None); |
| } |
| |
| fn expr_match(&mut self, expr: &ExprMatch) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(0); |
| self.word("match "); |
| self.wrap_exterior_struct(&expr.expr); |
| self.word("{"); |
| self.neverbreak(); |
| self.cbox(INDENT); |
| self.hardbreak_if_nonempty(); |
| self.inner_attrs(&expr.attrs); |
| for arm in &expr.arms { |
| self.arm(arm); |
| self.hardbreak(); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| self.end(); |
| } |
| |
| fn expr_method_call(&mut self, expr: &ExprMethodCall, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| let unindent_call_args = beginning_of_line && is_short_ident(&expr.receiver); |
| self.subexpr_method_call(expr, beginning_of_line, unindent_call_args); |
| self.end(); |
| } |
| |
| fn subexpr_method_call( |
| &mut self, |
| expr: &ExprMethodCall, |
| beginning_of_line: bool, |
| unindent_call_args: bool, |
| ) { |
| self.subexpr(&expr.receiver, beginning_of_line); |
| self.zerobreak_unless_short_ident(beginning_of_line, &expr.receiver); |
| self.word("."); |
| self.ident(&expr.method); |
| if let Some(turbofish) = &expr.turbofish { |
| self.method_turbofish(turbofish); |
| } |
| self.cbox(if unindent_call_args { -INDENT } else { 0 }); |
| self.word("("); |
| self.call_args(&expr.args); |
| self.word(")"); |
| self.end(); |
| } |
| |
| fn expr_paren(&mut self, expr: &ExprParen) { |
| self.outer_attrs(&expr.attrs); |
| self.word("("); |
| self.expr(&expr.expr); |
| self.word(")"); |
| } |
| |
| fn expr_path(&mut self, expr: &ExprPath) { |
| self.outer_attrs(&expr.attrs); |
| self.qpath(&expr.qself, &expr.path); |
| } |
| |
| fn expr_range(&mut self, expr: &ExprRange) { |
| self.outer_attrs(&expr.attrs); |
| if let Some(from) = &expr.from { |
| self.expr(from); |
| } |
| self.word(match expr.limits { |
| RangeLimits::HalfOpen(_) => "..", |
| RangeLimits::Closed(_) => "..=", |
| }); |
| if let Some(to) = &expr.to { |
| self.expr(to); |
| } |
| } |
| |
| fn expr_reference(&mut self, expr: &ExprReference) { |
| self.outer_attrs(&expr.attrs); |
| self.word("&"); |
| if expr.mutability.is_some() { |
| self.word("mut "); |
| } |
| self.expr(&expr.expr); |
| } |
| |
| fn expr_repeat(&mut self, expr: &ExprRepeat) { |
| self.outer_attrs(&expr.attrs); |
| self.word("["); |
| self.expr(&expr.expr); |
| self.word("; "); |
| self.expr(&expr.len); |
| self.word("]"); |
| } |
| |
| fn expr_return(&mut self, expr: &ExprReturn) { |
| self.outer_attrs(&expr.attrs); |
| self.word("return"); |
| if let Some(value) = &expr.expr { |
| self.nbsp(); |
| self.expr(value); |
| } |
| } |
| |
| fn expr_struct(&mut self, expr: &ExprStruct) { |
| self.expr_qualified_struct(&None, expr); |
| } |
| |
| fn expr_qualified_struct(&mut self, qself: &Option<QSelf>, expr: &ExprStruct) { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| self.ibox(-INDENT); |
| self.qpath(qself, &expr.path); |
| self.end(); |
| self.word(" {"); |
| self.space_if_nonempty(); |
| for field_value in expr.fields.iter().delimited() { |
| self.field_value(&field_value); |
| self.trailing_comma_or_space(field_value.is_last && expr.rest.is_none()); |
| } |
| if let Some(rest) = &expr.rest { |
| self.word(".."); |
| self.expr(rest); |
| self.space(); |
| } |
| self.offset(-INDENT); |
| self.end_with_max_width(34); |
| self.word("}"); |
| } |
| |
| fn expr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { |
| self.outer_attrs(&expr.attrs); |
| self.expr_beginning_of_line(&expr.expr, beginning_of_line); |
| self.word("?"); |
| } |
| |
| fn subexpr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { |
| self.subexpr(&expr.expr, beginning_of_line); |
| self.word("?"); |
| } |
| |
| fn expr_try_block(&mut self, expr: &ExprTryBlock) { |
| self.outer_attrs(&expr.attrs); |
| self.word("try "); |
| self.cbox(INDENT); |
| self.small_block(&expr.block, &expr.attrs); |
| self.end(); |
| } |
| |
| fn expr_tuple(&mut self, expr: &ExprTuple) { |
| self.outer_attrs(&expr.attrs); |
| self.word("("); |
| self.cbox(INDENT); |
| self.zerobreak(); |
| for elem in expr.elems.iter().delimited() { |
| self.expr(&elem); |
| if expr.elems.len() == 1 { |
| self.word(","); |
| self.zerobreak(); |
| } else { |
| self.trailing_comma(elem.is_last); |
| } |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word(")"); |
| } |
| |
| fn expr_type(&mut self, expr: &ExprType) { |
| self.outer_attrs(&expr.attrs); |
| self.ibox(INDENT); |
| self.ibox(-INDENT); |
| self.expr(&expr.expr); |
| self.end(); |
| self.space(); |
| self.word(": "); |
| self.ty(&expr.ty); |
| self.end(); |
| } |
| |
| fn expr_unary(&mut self, expr: &ExprUnary) { |
| self.outer_attrs(&expr.attrs); |
| self.unary_operator(&expr.op); |
| self.expr(&expr.expr); |
| } |
| |
| fn expr_unsafe(&mut self, expr: &ExprUnsafe) { |
| self.outer_attrs(&expr.attrs); |
| self.word("unsafe {"); |
| self.cbox(INDENT); |
| self.space_if_nonempty(); |
| self.inner_attrs(&expr.attrs); |
| for stmt in expr.block.stmts.iter().delimited() { |
| if stmt.is_first && stmt.is_last { |
| if let Stmt::Expr(expr) = &*stmt { |
| self.expr(expr); |
| self.space(); |
| continue; |
| } |
| } |
| self.stmt(&stmt); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| } |
| |
| #[cfg(not(feature = "verbatim"))] |
| fn expr_verbatim(&mut self, expr: &TokenStream) { |
| if !expr.is_empty() { |
| unimplemented!("Expr::Verbatim `{}`", expr); |
| } |
| } |
| |
| #[cfg(feature = "verbatim")] |
| fn expr_verbatim(&mut self, tokens: &TokenStream) { |
| use syn::parse::{Parse, ParseStream, Result}; |
| use syn::{braced, BoundLifetimes}; |
| |
| enum ExprVerbatim { |
| Empty, |
| Infer, |
| RawReference(RawReference), |
| ConstBlock(ConstBlock), |
| ClosureWithLifetimes(ClosureWithLifetimes), |
| QualifiedStruct(QualifiedStruct), |
| } |
| |
| struct RawReference { |
| mutable: bool, |
| expr: Expr, |
| } |
| |
| struct ConstBlock { |
| attrs: Vec<Attribute>, |
| block: Block, |
| } |
| |
| struct ClosureWithLifetimes { |
| lifetimes: BoundLifetimes, |
| closure: ExprClosure, |
| } |
| |
| struct QualifiedStruct { |
| qself: QSelf, |
| strct: ExprStruct, |
| } |
| |
| mod kw { |
| syn::custom_keyword!(raw); |
| } |
| |
| impl Parse for ExprVerbatim { |
| fn parse(input: ParseStream) -> Result<Self> { |
| let lookahead = input.lookahead1(); |
| if input.is_empty() { |
| Ok(ExprVerbatim::Empty) |
| } else if lookahead.peek(Token![_]) { |
| input.parse::<Token![_]>()?; |
| Ok(ExprVerbatim::Infer) |
| } else if lookahead.peek(Token![&]) { |
| input.parse::<Token![&]>()?; |
| input.parse::<kw::raw>()?; |
| let mutable = input.parse::<Option<Token![mut]>>()?.is_some(); |
| if !mutable { |
| input.parse::<Token![const]>()?; |
| } |
| let expr: Expr = input.parse()?; |
| Ok(ExprVerbatim::RawReference(RawReference { mutable, expr })) |
| } else if lookahead.peek(Token![const]) { |
| input.parse::<Token![const]>()?; |
| let content; |
| let brace_token = braced!(content in input); |
| let attrs = content.call(Attribute::parse_inner)?; |
| let stmts = content.call(Block::parse_within)?; |
| Ok(ExprVerbatim::ConstBlock(ConstBlock { |
| attrs, |
| block: Block { brace_token, stmts }, |
| })) |
| } else if lookahead.peek(Token![for]) { |
| let lifetimes = input.parse()?; |
| let closure = input.parse()?; |
| Ok(ExprVerbatim::ClosureWithLifetimes(ClosureWithLifetimes { |
| lifetimes, |
| closure, |
| })) |
| } else if lookahead.peek(Token![<]) { |
| let path: ExprPath = input.parse()?; |
| let content; |
| let mut expr = QualifiedStruct { |
| qself: path.qself.unwrap(), |
| strct: ExprStruct { |
| attrs: Vec::new(), |
| brace_token: braced!(content in input), |
| path: path.path, |
| fields: Punctuated::new(), |
| dot2_token: None, |
| rest: None, |
| }, |
| }; |
| while !content.is_empty() { |
| if content.peek(Token![..]) { |
| expr.strct.dot2_token = Some(content.parse()?); |
| if !content.is_empty() { |
| expr.strct.rest = Some(Box::new(content.parse()?)); |
| } |
| break; |
| } |
| expr.strct.fields.push(content.parse()?); |
| if content.is_empty() { |
| break; |
| } |
| let punct: Token![,] = content.parse()?; |
| expr.strct.fields.push_punct(punct); |
| } |
| Ok(ExprVerbatim::QualifiedStruct(expr)) |
| } else { |
| Err(lookahead.error()) |
| } |
| } |
| } |
| |
| let expr: ExprVerbatim = match syn::parse2(tokens.clone()) { |
| Ok(expr) => expr, |
| Err(_) => unimplemented!("Expr::Verbatim `{}`", tokens), |
| }; |
| |
| match expr { |
| ExprVerbatim::Empty => {} |
| ExprVerbatim::Infer => { |
| self.word("_"); |
| } |
| ExprVerbatim::RawReference(expr) => { |
| self.word("&raw "); |
| self.word(if expr.mutable { "mut " } else { "const " }); |
| self.expr(&expr.expr); |
| } |
| ExprVerbatim::ConstBlock(expr) => { |
| self.outer_attrs(&expr.attrs); |
| self.cbox(INDENT); |
| self.word("const "); |
| self.small_block(&expr.block, &expr.attrs); |
| self.end(); |
| } |
| ExprVerbatim::ClosureWithLifetimes(expr) => { |
| self.bound_lifetimes(&expr.lifetimes); |
| self.expr_closure(&expr.closure); |
| } |
| ExprVerbatim::QualifiedStruct(expr) => { |
| self.expr_qualified_struct(&Some(expr.qself), &expr.strct); |
| } |
| } |
| } |
| |
| fn expr_while(&mut self, expr: &ExprWhile) { |
| self.outer_attrs(&expr.attrs); |
| if let Some(label) = &expr.label { |
| self.label(label); |
| } |
| self.word("while "); |
| self.wrap_exterior_struct(&expr.cond); |
| self.word("{"); |
| self.neverbreak(); |
| self.cbox(INDENT); |
| self.hardbreak_if_nonempty(); |
| self.inner_attrs(&expr.attrs); |
| for stmt in &expr.body.stmts { |
| self.stmt(stmt); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| } |
| |
| fn expr_yield(&mut self, expr: &ExprYield) { |
| self.outer_attrs(&expr.attrs); |
| self.word("yield"); |
| if let Some(value) = &expr.expr { |
| self.nbsp(); |
| self.expr(value); |
| } |
| } |
| |
| fn label(&mut self, label: &Label) { |
| self.lifetime(&label.name); |
| self.word(": "); |
| } |
| |
| fn field_value(&mut self, field_value: &FieldValue) { |
| self.outer_attrs(&field_value.attrs); |
| self.member(&field_value.member); |
| if field_value.colon_token.is_some() { |
| self.word(": "); |
| self.ibox(0); |
| self.expr(&field_value.expr); |
| self.end(); |
| } |
| } |
| |
| fn arm(&mut self, arm: &Arm) { |
| self.outer_attrs(&arm.attrs); |
| self.ibox(0); |
| self.pat(&arm.pat); |
| if let Some((_if_token, guard)) = &arm.guard { |
| self.word(" if "); |
| self.expr(guard); |
| } |
| self.word(" =>"); |
| let empty_block; |
| let mut body = &*arm.body; |
| while let Expr::Block(expr) = body { |
| if expr.attrs.is_empty() && expr.label.is_none() { |
| let mut stmts = expr.block.stmts.iter(); |
| if let (Some(Stmt::Expr(inner)), None) = (stmts.next(), stmts.next()) { |
| body = inner; |
| continue; |
| } |
| } |
| break; |
| } |
| if let Expr::Tuple(expr) = body { |
| if expr.elems.is_empty() && expr.attrs.is_empty() { |
| empty_block = Expr::Block(ExprBlock { |
| attrs: Vec::new(), |
| label: None, |
| block: Block { |
| brace_token: token::Brace::default(), |
| stmts: Vec::new(), |
| }, |
| }); |
| body = &empty_block; |
| } |
| } |
| if let Expr::Block(body) = body { |
| self.nbsp(); |
| if let Some(label) = &body.label { |
| self.label(label); |
| } |
| self.word("{"); |
| self.neverbreak(); |
| self.cbox(INDENT); |
| self.hardbreak_if_nonempty(); |
| self.inner_attrs(&body.attrs); |
| for stmt in &body.block.stmts { |
| self.stmt(stmt); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word("}"); |
| self.end(); |
| } else { |
| self.nbsp(); |
| self.neverbreak(); |
| self.cbox(INDENT); |
| self.scan_break(BreakToken { |
| pre_break: Some('{'), |
| ..BreakToken::default() |
| }); |
| self.expr(body); |
| self.scan_break(BreakToken { |
| offset: -INDENT, |
| pre_break: stmt::add_semi(body).then(|| ';'), |
| post_break: Some('}'), |
| no_break: requires_terminator(body).then(|| ','), |
| ..BreakToken::default() |
| }); |
| self.end(); |
| self.end(); |
| } |
| } |
| |
| fn method_turbofish(&mut self, turbofish: &MethodTurbofish) { |
| self.word("::<"); |
| self.cbox(INDENT); |
| self.zerobreak(); |
| for arg in turbofish.args.iter().delimited() { |
| self.generic_method_argument(&arg); |
| self.trailing_comma(arg.is_last); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| self.word(">"); |
| } |
| |
| fn generic_method_argument(&mut self, generic: &GenericMethodArgument) { |
| match generic { |
| GenericMethodArgument::Type(arg) => self.ty(arg), |
| GenericMethodArgument::Const(arg) => self.expr(arg), |
| } |
| } |
| |
| fn call_args(&mut self, args: &Punctuated<Expr, Token![,]>) { |
| let mut iter = args.iter(); |
| match (iter.next(), iter.next()) { |
| (Some(expr), None) if is_blocklike(expr) => { |
| self.expr(expr); |
| } |
| _ => { |
| self.cbox(INDENT); |
| self.zerobreak(); |
| for arg in args.iter().delimited() { |
| self.expr(&arg); |
| self.trailing_comma(arg.is_last); |
| } |
| self.offset(-INDENT); |
| self.end(); |
| } |
| } |
| } |
| |
| fn small_block(&mut self, block: &Block, attrs: &[Attribute]) { |
| self.word("{"); |
| if attr::has_inner(attrs) || !block.stmts.is_empty() { |
| self.space(); |
| self.inner_attrs(attrs); |
| match (block.stmts.get(0), block.stmts.get(1)) { |
| (Some(Stmt::Expr(expr)), None) if stmt::break_after(expr) => { |
| self.ibox(0); |
| self.expr_beginning_of_line(expr, true); |
| self.end(); |
| self.space(); |
| } |
| _ => { |
| for stmt in &block.stmts { |
| self.stmt(stmt); |
| } |
| } |
| } |
| self.offset(-INDENT); |
| } |
| self.word("}"); |
| } |
| |
| pub fn member(&mut self, member: &Member) { |
| match member { |
| Member::Named(ident) => self.ident(ident), |
| Member::Unnamed(index) => self.index(index), |
| } |
| } |
| |
| fn index(&mut self, member: &Index) { |
| self.word(member.index.to_string()); |
| } |
| |
| fn binary_operator(&mut self, op: &BinOp) { |
| self.word(match op { |
| BinOp::Add(_) => "+", |
| BinOp::Sub(_) => "-", |
| BinOp::Mul(_) => "*", |
| BinOp::Div(_) => "/", |
| BinOp::Rem(_) => "%", |
| BinOp::And(_) => "&&", |
| BinOp::Or(_) => "||", |
| BinOp::BitXor(_) => "^", |
| BinOp::BitAnd(_) => "&", |
| BinOp::BitOr(_) => "|", |
| BinOp::Shl(_) => "<<", |
| BinOp::Shr(_) => ">>", |
| BinOp::Eq(_) => "==", |
| BinOp::Lt(_) => "<", |
| BinOp::Le(_) => "<=", |
| BinOp::Ne(_) => "!=", |
| BinOp::Ge(_) => ">=", |
| BinOp::Gt(_) => ">", |
| BinOp::AddEq(_) => "+=", |
| BinOp::SubEq(_) => "-=", |
| BinOp::MulEq(_) => "*=", |
| BinOp::DivEq(_) => "/=", |
| BinOp::RemEq(_) => "%=", |
| BinOp::BitXorEq(_) => "^=", |
| BinOp::BitAndEq(_) => "&=", |
| BinOp::BitOrEq(_) => "|=", |
| BinOp::ShlEq(_) => "<<=", |
| BinOp::ShrEq(_) => ">>=", |
| }); |
| } |
| |
| fn unary_operator(&mut self, op: &UnOp) { |
| self.word(match op { |
| UnOp::Deref(_) => "*", |
| UnOp::Not(_) => "!", |
| UnOp::Neg(_) => "-", |
| }); |
| } |
| |
| fn zerobreak_unless_short_ident(&mut self, beginning_of_line: bool, expr: &Expr) { |
| if beginning_of_line && is_short_ident(expr) { |
| return; |
| } |
| self.zerobreak(); |
| } |
| } |
| |
| pub fn requires_terminator(expr: &Expr) -> bool { |
| // see https://github.com/rust-lang/rust/blob/2679c38fc/src/librustc_ast/util/classify.rs#L7-L25 |
| match expr { |
| Expr::Unsafe(_) |
| | Expr::Block(_) |
| | Expr::If(_) |
| | Expr::Match(_) |
| | Expr::While(_) |
| | Expr::Loop(_) |
| | Expr::ForLoop(_) |
| | Expr::Async(_) |
| | Expr::TryBlock(_) => false, |
| _ => true, |
| } |
| } |
| |
| // Expressions that syntactically contain an "exterior" struct literal i.e. not |
| // surrounded by any parens or other delimiters. For example `X { y: 1 }`, `X { |
| // y: 1 }.method()`, `foo == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X |
| // { y: 1 }) == foo` does not. |
| fn contains_exterior_struct_lit(expr: &Expr) -> bool { |
| match expr { |
| Expr::Struct(_) => true, |
| |
| Expr::Assign(ExprAssign { left, right, .. }) |
| | Expr::AssignOp(ExprAssignOp { left, right, .. }) |
| | Expr::Binary(ExprBinary { left, right, .. }) => { |
| // X { y: 1 } + X { y: 2 } |
| contains_exterior_struct_lit(left) || contains_exterior_struct_lit(right) |
| } |
| |
| Expr::Await(ExprAwait { base: e, .. }) |
| | Expr::Box(ExprBox { expr: e, .. }) |
| | Expr::Cast(ExprCast { expr: e, .. }) |
| | Expr::Field(ExprField { base: e, .. }) |
| | Expr::Index(ExprIndex { expr: e, .. }) |
| | Expr::MethodCall(ExprMethodCall { receiver: e, .. }) |
| | Expr::Reference(ExprReference { expr: e, .. }) |
| | Expr::Type(ExprType { expr: e, .. }) |
| | Expr::Unary(ExprUnary { expr: e, .. }) => { |
| // &X { y: 1 }, X { y: 1 }.y |
| contains_exterior_struct_lit(e) |
| } |
| |
| _ => false, |
| } |
| } |
| |
| fn needs_newline_if_wrap(expr: &Expr) -> bool { |
| match expr { |
| Expr::Array(_) |
| | Expr::Async(_) |
| | Expr::Block(_) |
| | Expr::Break(ExprBreak { expr: None, .. }) |
| | Expr::Closure(_) |
| | Expr::Continue(_) |
| | Expr::ForLoop(_) |
| | Expr::If(_) |
| | Expr::Lit(_) |
| | Expr::Loop(_) |
| | Expr::Macro(_) |
| | Expr::Match(_) |
| | Expr::Path(_) |
| | Expr::Range(ExprRange { to: None, .. }) |
| | Expr::Repeat(_) |
| | Expr::Return(ExprReturn { expr: None, .. }) |
| | Expr::Struct(_) |
| | Expr::TryBlock(_) |
| | Expr::Tuple(_) |
| | Expr::Unsafe(_) |
| | Expr::Verbatim(_) |
| | Expr::While(_) |
| | Expr::Yield(ExprYield { expr: None, .. }) => false, |
| |
| Expr::Assign(_) |
| | Expr::AssignOp(_) |
| | Expr::Await(_) |
| | Expr::Binary(_) |
| | Expr::Cast(_) |
| | Expr::Field(_) |
| | Expr::Index(_) |
| | Expr::MethodCall(_) |
| | Expr::Type(_) => true, |
| |
| Expr::Box(ExprBox { expr: e, .. }) |
| | Expr::Break(ExprBreak { expr: Some(e), .. }) |
| | Expr::Call(ExprCall { func: e, .. }) |
| | Expr::Group(ExprGroup { expr: e, .. }) |
| | Expr::Let(ExprLet { expr: e, .. }) |
| | Expr::Paren(ExprParen { expr: e, .. }) |
| | Expr::Range(ExprRange { to: Some(e), .. }) |
| | Expr::Reference(ExprReference { expr: e, .. }) |
| | Expr::Return(ExprReturn { expr: Some(e), .. }) |
| | Expr::Try(ExprTry { expr: e, .. }) |
| | Expr::Unary(ExprUnary { expr: e, .. }) |
| | Expr::Yield(ExprYield { expr: Some(e), .. }) => needs_newline_if_wrap(e), |
| |
| #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
| _ => false, |
| } |
| } |
| |
| fn is_short_ident(expr: &Expr) -> bool { |
| if let Expr::Path(expr) = expr { |
| if expr.attrs.is_empty() |
| && expr.qself.is_none() |
| && expr.path.leading_colon.is_none() |
| && expr.path.segments.len() == 1 |
| && expr.path.segments[0].ident.to_string().len() as isize <= INDENT |
| { |
| if let PathArguments::None = expr.path.segments[0].arguments { |
| return true; |
| } |
| } |
| } |
| false |
| } |
| |
| fn is_blocklike(expr: &Expr) -> bool { |
| match expr { |
| Expr::Array(ExprArray { attrs, .. }) |
| | Expr::Async(ExprAsync { attrs, .. }) |
| | Expr::Block(ExprBlock { attrs, .. }) |
| | Expr::Closure(ExprClosure { attrs, .. }) |
| | Expr::Struct(ExprStruct { attrs, .. }) |
| | Expr::TryBlock(ExprTryBlock { attrs, .. }) |
| | Expr::Tuple(ExprTuple { attrs, .. }) |
| | Expr::Unsafe(ExprUnsafe { attrs, .. }) => !attr::has_outer(attrs), |
| _ => false, |
| } |
| } |