aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Maurer <mmaurer@google.com>2023-05-26 20:23:04 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-05-26 20:23:04 +0000
commita759152d73848994979f9d1f3ea9fc1aa8134827 (patch)
tree9fc06f5a5d569b3a692bae365da57117c240fff2
parent017cab358ebcff2da4da1e9034212024ee5380a1 (diff)
parentee6cb37112f18c4a56548c628e9c44925980c728 (diff)
downloadprettyplease-a759152d73848994979f9d1f3ea9fc1aa8134827.tar.gz
Upgrade prettyplease to 0.2.6 am: ee6cb37112
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/prettyplease/+/2601405 Change-Id: Iff1fff0d6014016ce2ffb7883335a16cfaaf5775 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml12
-rw-r--r--Android.bp2
-rw-r--r--Cargo.toml11
-rw-r--r--Cargo.toml.orig34
-rw-r--r--METADATA13
-rw-r--r--README.md4
-rw-r--r--src/algorithm.rs2
-rw-r--r--src/attr.rs56
-rw-r--r--src/data.rs31
-rw-r--r--src/expr.rs424
-rw-r--r--src/generics.rs103
-rw-r--r--src/item.rs986
-rw-r--r--src/lib.rs6
-rw-r--r--src/lit.rs2
-rw-r--r--src/mac.rs52
-rw-r--r--src/pat.rs118
-rw-r--r--src/path.rs89
-rw-r--r--src/stmt.rs146
-rw-r--r--src/ty.rs92
20 files changed, 1655 insertions, 530 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 3e35b72..2ede8cc 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "81780e0ebdb1f8df7c36b39a02e606e60581dce9"
+ "sha1": "f69383aff4049036f11f3a3b4b927f28f96fa60f"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ca27e6a..fa508cd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -53,6 +53,18 @@ jobs:
- run: cargo run --manifest-path cargo-expand/update/Cargo.toml
- run: git diff --exit-code
+ fuzz:
+ name: Fuzz
+ needs: pre_ci
+ if: needs.pre_ci.outputs.continue
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@nightly
+ - uses: dtolnay/install@cargo-fuzz
+ - run: cargo fuzz check
+
clippy:
name: Clippy
runs-on: ubuntu-latest
diff --git a/Android.bp b/Android.bp
index 3e7383d..b89003e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,7 +7,7 @@ rust_library_host {
name: "libprettyplease",
crate_name: "prettyplease",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.25",
+ cargo_pkg_version: "0.2.6",
srcs: ["src/lib.rs"],
edition: "2021",
rustlibs: [
diff --git a/Cargo.toml b/Cargo.toml
index e77b675..744d02e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
rust-version = "1.56"
name = "prettyplease"
-version = "0.1.25"
+version = "0.2.6"
authors = ["David Tolnay <dtolnay@gmail.com>"]
-links = "prettyplease01"
+links = "prettyplease02"
exclude = ["cargo-expand"]
autoexamples = false
description = "A minimal `syn` syntax tree pretty-printer"
@@ -26,6 +26,9 @@ categories = ["development-tools"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/prettyplease"
+[package.metadata.playground]
+features = ["verbatim"]
+
[lib]
doc-scrape-examples = false
@@ -34,12 +37,12 @@ version = "1.0"
default-features = false
[dependencies.syn]
-version = "1.0.90"
+version = "2.0.16"
features = ["full"]
default-features = false
[dev-dependencies.syn]
-version = "1.0.90"
+version = "2.0.16"
features = ["parsing"]
default-features = false
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..c902b61
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,34 @@
+[package]
+name = "prettyplease"
+version = "0.2.6"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+autoexamples = false
+categories = ["development-tools"]
+description = "A minimal `syn` syntax tree pretty-printer"
+documentation = "https://docs.rs/prettyplease"
+edition = "2021"
+exclude = ["cargo-expand"]
+keywords = ["rustfmt"]
+license = "MIT OR Apache-2.0"
+links = "prettyplease02"
+repository = "https://github.com/dtolnay/prettyplease"
+rust-version = "1.56"
+
+[features]
+verbatim = ["syn/parsing"]
+
+[dependencies]
+proc-macro2 = { version = "1.0", default-features = false }
+syn = { version = "2.0.16", default-features = false, features = ["full"] }
+
+[dev-dependencies]
+syn = { version = "2.0.16", default-features = false, features = ["parsing"] }
+
+[lib]
+doc-scrape-examples = false
+
+[package.metadata.playground]
+features = ["verbatim"]
+
+[workspace]
+members = ["cargo-expand/update", "examples/update"]
diff --git a/METADATA b/METADATA
index b433848..6d6bed3 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/prettyplease
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "prettyplease"
description: "A minimal `syn` syntax tree pretty-printer"
third_party {
@@ -7,14 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/prettyplease/prettyplease-0.1.25.crate"
+ value: "https://static.crates.io/crates/prettyplease/prettyplease-0.2.6.crate"
}
- version: "0.1.25"
- # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ version: "0.2.6"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 3
- day: 22
+ month: 5
+ day: 23
}
}
diff --git a/README.md b/README.md
index 5695972..bd0439b 100644
--- a/README.md
+++ b/README.md
@@ -167,8 +167,8 @@ from rustfmt-formatted code.
```rust
// [dependencies]
-// prettyplease = "0.1"
-// syn = { version = "1", default-features = false, features = ["full", "parsing"] }
+// prettyplease = "0.2"
+// syn = { version = "2", default-features = false, features = ["full", "parsing"] }
const INPUT: &str = stringify! {
use crate::{
diff --git a/src/algorithm.rs b/src/algorithm.rs
index b6dea57..6e2b961 100644
--- a/src/algorithm.rs
+++ b/src/algorithm.rs
@@ -251,7 +251,7 @@ impl Printer {
fn check_stack(&mut self, mut depth: usize) {
while let Some(&index) = self.scan_stack.back() {
- let mut entry = &mut self.buf[index];
+ let entry = &mut self.buf[index];
match entry.token {
Token::Begin(_) => {
if depth == 0 {
diff --git a/src/attr.rs b/src/attr.rs
index cd36ce5..0388d66 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -1,7 +1,8 @@
use crate::algorithm::Printer;
+use crate::path::PathKind;
use crate::INDENT;
-use proc_macro2::{Delimiter, TokenStream, TokenTree};
-use syn::{AttrStyle, Attribute, Lit, PathArguments};
+use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
+use syn::{AttrStyle, Attribute, Expr, Lit, MacroDelimiter, Meta, MetaList, MetaNameValue};
impl Printer {
pub fn outer_attrs(&mut self, attrs: &[Attribute]) {
@@ -74,12 +75,36 @@ impl Printer {
AttrStyle::Inner(_) => "#!",
});
self.word("[");
- self.path(&attr.path);
- self.attr_tokens(attr.tokens.clone());
+ self.meta(&attr.meta);
self.word("]");
self.space();
}
+ fn meta(&mut self, meta: &Meta) {
+ match meta {
+ Meta::Path(path) => self.path(path, PathKind::Simple),
+ Meta::List(meta) => self.meta_list(meta),
+ Meta::NameValue(meta) => self.meta_name_value(meta),
+ }
+ }
+
+ fn meta_list(&mut self, meta: &MetaList) {
+ self.path(&meta.path, PathKind::Simple);
+ let delimiter = match meta.delimiter {
+ MacroDelimiter::Paren(_) => Delimiter::Parenthesis,
+ MacroDelimiter::Brace(_) => Delimiter::Brace,
+ MacroDelimiter::Bracket(_) => Delimiter::Bracket,
+ };
+ let group = Group::new(delimiter, meta.tokens.clone());
+ self.attr_tokens(TokenStream::from(TokenTree::Group(group)));
+ }
+
+ fn meta_name_value(&mut self, meta: &MetaNameValue) {
+ self.path(&meta.path, PathKind::Simple);
+ self.word(" = ");
+ self.expr(&meta.value);
+ }
+
fn attr_tokens(&mut self, tokens: TokenStream) {
let mut stack = Vec::new();
stack.push((tokens.into_iter().peekable(), Delimiter::None));
@@ -184,26 +209,15 @@ impl Printer {
}
fn value_of_attribute(requested: &str, attr: &Attribute) -> Option<String> {
- let is_doc = attr.path.leading_colon.is_none()
- && attr.path.segments.len() == 1
- && matches!(attr.path.segments[0].arguments, PathArguments::None)
- && attr.path.segments[0].ident == requested;
- if !is_doc {
- return None;
- }
- let mut tokens = attr.tokens.clone().into_iter();
- match tokens.next() {
- Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {}
+ let value = match &attr.meta {
+ Meta::NameValue(meta) if meta.path.is_ident(requested) => &meta.value,
_ => return None,
- }
- let literal = match tokens.next() {
- Some(TokenTree::Literal(literal)) => literal,
+ };
+ let lit = match value {
+ Expr::Lit(expr) if expr.attrs.is_empty() => &expr.lit,
_ => return None,
};
- if tokens.next().is_some() {
- return None;
- }
- match Lit::new(literal) {
+ match lit {
Lit::Str(string) => Some(string.value()),
_ => None,
}
diff --git a/src/data.rs b/src/data.rs
index 7767981..d823ee3 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -1,10 +1,8 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
use crate::INDENT;
-use syn::{
- Field, Fields, FieldsUnnamed, PathArguments, Variant, VisCrate, VisPublic, VisRestricted,
- Visibility,
-};
+use syn::{Field, Fields, FieldsUnnamed, Variant, VisRestricted, Visibility};
impl Printer {
pub fn variant(&mut self, variant: &Variant) {
@@ -60,36 +58,21 @@ impl Printer {
pub fn visibility(&mut self, vis: &Visibility) {
match vis {
- Visibility::Public(vis) => self.vis_public(vis),
- Visibility::Crate(vis) => self.vis_crate(vis),
+ Visibility::Public(_) => self.word("pub "),
Visibility::Restricted(vis) => self.vis_restricted(vis),
Visibility::Inherited => {}
}
}
- fn vis_public(&mut self, vis: &VisPublic) {
- let _ = vis;
- self.word("pub ");
- }
-
- fn vis_crate(&mut self, vis: &VisCrate) {
- let _ = vis;
- self.word("crate ");
- }
-
fn vis_restricted(&mut self, vis: &VisRestricted) {
self.word("pub(");
- let omit_in = vis.path.leading_colon.is_none()
- && vis.path.segments.len() == 1
- && matches!(vis.path.segments[0].arguments, PathArguments::None)
- && matches!(
- vis.path.segments[0].ident.to_string().as_str(),
- "self" | "super" | "crate",
- );
+ let omit_in = vis.path.get_ident().map_or(false, |ident| {
+ matches!(ident.to_string().as_str(), "self" | "super" | "crate")
+ });
if !omit_in {
self.word("in ");
}
- self.path(&vis.path);
+ self.path(&vis.path, PathKind::Simple);
self.word(") ");
}
}
diff --git a/src/expr.rs b/src/expr.rs
index 0689595..92c50e7 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1,18 +1,19 @@
use crate::algorithm::{BreakToken, Printer};
use crate::attr;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
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,
+ token, Arm, Attribute, BinOp, Block, Expr, ExprArray, ExprAssign, ExprAsync, ExprAwait,
+ ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprConst, ExprContinue,
+ ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, 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,
+ ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe,
+ ExprWhile, ExprYield, FieldValue, Index, Label, Member, RangeLimits, ReturnType, Stmt, Token,
+ UnOp,
};
impl Printer {
@@ -20,22 +21,22 @@ impl Printer {
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::Const(expr) => self.expr_const(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::Infer(expr) => self.expr_infer(expr),
Expr::Let(expr) => self.expr_let(expr),
Expr::Lit(expr) => self.expr_lit(expr),
Expr::Loop(expr) => self.expr_loop(expr),
@@ -52,7 +53,6 @@ impl Printer {
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),
@@ -90,8 +90,6 @@ impl Printer {
}
}
- // 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 {
@@ -133,19 +131,6 @@ impl Printer {
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 ");
@@ -193,12 +178,6 @@ impl Printer {
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");
@@ -242,12 +221,18 @@ impl Printer {
fn expr_closure(&mut self, expr: &ExprClosure) {
self.outer_attrs(&expr.attrs);
self.ibox(0);
- if expr.asyncness.is_some() {
- self.word("async ");
+ if let Some(bound_lifetimes) = &expr.lifetimes {
+ self.bound_lifetimes(bound_lifetimes);
+ }
+ if expr.constness.is_some() {
+ self.word("const ");
}
if expr.movability.is_some() {
self.word("static ");
}
+ if expr.asyncness.is_some() {
+ self.word("async ");
+ }
if expr.capture.is_some() {
self.word("move ");
}
@@ -311,6 +296,14 @@ impl Printer {
self.end();
}
+ pub fn expr_const(&mut self, expr: &ExprConst) {
+ self.outer_attrs(&expr.attrs);
+ self.word("const ");
+ self.cbox(INDENT);
+ self.small_block(&expr.block, &expr.attrs);
+ self.end();
+ }
+
fn expr_continue(&mut self, expr: &ExprContinue) {
self.outer_attrs(&expr.attrs);
self.word("continue");
@@ -435,6 +428,11 @@ impl Printer {
self.word("]");
}
+ fn expr_infer(&mut self, expr: &ExprInfer) {
+ self.outer_attrs(&expr.attrs);
+ self.word("_");
+ }
+
fn expr_let(&mut self, expr: &ExprLet) {
self.outer_attrs(&expr.attrs);
self.ibox(INDENT);
@@ -477,9 +475,10 @@ impl Printer {
self.word("}");
}
- fn expr_macro(&mut self, expr: &ExprMacro) {
+ pub fn expr_macro(&mut self, expr: &ExprMacro) {
self.outer_attrs(&expr.attrs);
- self.mac(&expr.mac, None);
+ let semicolon = false;
+ self.mac(&expr.mac, None, semicolon);
}
fn expr_match(&mut self, expr: &ExprMatch) {
@@ -521,7 +520,7 @@ impl Printer {
self.word(".");
self.ident(&expr.method);
if let Some(turbofish) = &expr.turbofish {
- self.method_turbofish(turbofish);
+ self.angle_bracketed_generic_arguments(turbofish, PathKind::Expr);
}
self.cbox(if unindent_call_args { -INDENT } else { 0 });
self.word("(");
@@ -537,22 +536,22 @@ impl Printer {
self.word(")");
}
- fn expr_path(&mut self, expr: &ExprPath) {
+ pub fn expr_path(&mut self, expr: &ExprPath) {
self.outer_attrs(&expr.attrs);
- self.qpath(&expr.qself, &expr.path);
+ self.qpath(&expr.qself, &expr.path, PathKind::Expr);
}
- fn expr_range(&mut self, expr: &ExprRange) {
+ pub fn expr_range(&mut self, expr: &ExprRange) {
self.outer_attrs(&expr.attrs);
- if let Some(from) = &expr.from {
- self.expr(from);
+ if let Some(start) = &expr.start {
+ self.expr(start);
}
self.word(match expr.limits {
RangeLimits::HalfOpen(_) => "..",
RangeLimits::Closed(_) => "..=",
});
- if let Some(to) = &expr.to {
- self.expr(to);
+ if let Some(end) = &expr.end {
+ self.expr(end);
}
}
@@ -584,14 +583,10 @@ impl Printer {
}
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.qpath(&expr.qself, &expr.path, PathKind::Expr);
self.end();
self.word(" {");
self.space_if_nonempty();
@@ -647,18 +642,6 @@ impl Printer {
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);
@@ -667,23 +650,10 @@ impl Printer {
fn expr_unsafe(&mut self, expr: &ExprUnsafe) {
self.outer_attrs(&expr.attrs);
- self.word("unsafe {");
+ 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.small_block(&expr.block, &expr.attrs);
self.end();
- self.word("}");
}
#[cfg(not(feature = "verbatim"))]
@@ -696,15 +666,17 @@ impl Printer {
#[cfg(feature = "verbatim")]
fn expr_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
- use syn::{braced, BoundLifetimes};
+ use syn::{parenthesized, Ident};
enum ExprVerbatim {
Empty,
- Infer,
+ Builtin(Builtin),
RawReference(RawReference),
- ConstBlock(ConstBlock),
- ClosureWithLifetimes(ClosureWithLifetimes),
- QualifiedStruct(QualifiedStruct),
+ }
+
+ struct Builtin {
+ name: Ident,
+ args: TokenStream,
}
struct RawReference {
@@ -712,22 +684,8 @@ impl Printer {
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!(builtin);
syn::custom_keyword!(raw);
}
@@ -736,9 +694,14 @@ impl Printer {
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(kw::builtin) {
+ input.parse::<kw::builtin>()?;
+ input.parse::<Token![#]>()?;
+ let name: Ident = input.parse()?;
+ let args;
+ parenthesized!(args in input);
+ let args: TokenStream = args.parse()?;
+ Ok(ExprVerbatim::Builtin(Builtin { name, args }))
} else if lookahead.peek(Token![&]) {
input.parse::<Token![&]>()?;
input.parse::<kw::raw>()?;
@@ -748,53 +711,6 @@ impl Printer {
}
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())
}
@@ -808,28 +724,27 @@ impl Printer {
match expr {
ExprVerbatim::Empty => {}
- ExprVerbatim::Infer => {
- self.word("_");
+ ExprVerbatim::Builtin(expr) => {
+ self.word("builtin # ");
+ self.ident(&expr.name);
+ self.word("(");
+ if !expr.args.is_empty() {
+ self.cbox(INDENT);
+ self.zerobreak();
+ self.ibox(0);
+ self.macro_rules_tokens(expr.args, false);
+ self.end();
+ self.zerobreak();
+ self.offset(-INDENT);
+ self.end();
+ }
+ 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);
- }
}
}
@@ -892,7 +807,7 @@ impl Printer {
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()) {
+ if let (Some(Stmt::Expr(inner, None)), None) = (stmts.next(), stmts.next()) {
body = inner;
continue;
}
@@ -937,7 +852,7 @@ impl Printer {
pre_break: Some('{'),
..BreakToken::default()
});
- self.expr(body);
+ self.expr_beginning_of_line(body, true);
self.scan_break(BreakToken {
offset: -INDENT,
pre_break: stmt::add_semi(body).then(|| ';'),
@@ -950,26 +865,6 @@ impl Printer {
}
}
- 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()) {
@@ -989,13 +884,13 @@ impl Printer {
}
}
- fn small_block(&mut self, block: &Block, attrs: &[Attribute]) {
+ pub 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) => {
+ (Some(Stmt::Expr(expr, None)), None) if stmt::break_after(expr) => {
self.ibox(0);
self.expr_beginning_of_line(expr, true);
self.end();
@@ -1043,16 +938,18 @@ impl Printer {
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(_) => ">>=",
+ BinOp::AddAssign(_) => "+=",
+ BinOp::SubAssign(_) => "-=",
+ BinOp::MulAssign(_) => "*=",
+ BinOp::DivAssign(_) => "/=",
+ BinOp::RemAssign(_) => "%=",
+ BinOp::BitXorAssign(_) => "^=",
+ BinOp::BitAndAssign(_) => "&=",
+ BinOp::BitOrAssign(_) => "|=",
+ BinOp::ShlAssign(_) => "<<=",
+ BinOp::ShrAssign(_) => ">>=",
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown BinOp"),
});
}
@@ -1061,6 +958,8 @@ impl Printer {
UnOp::Deref(_) => "*",
UnOp::Not(_) => "!",
UnOp::Neg(_) => "-",
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown UnOp"),
});
}
@@ -1073,17 +972,49 @@ impl Printer {
}
pub fn requires_terminator(expr: &Expr) -> bool {
- // see https://github.com/rust-lang/rust/blob/2679c38fc/src/librustc_ast/util/classify.rs#L7-L25
+ // see https://github.com/rust-lang/rust/blob/a266f1199/compiler/rustc_ast/src/util/classify.rs#L7-L26
match expr {
- Expr::Unsafe(_)
- | Expr::Block(_)
- | Expr::If(_)
+ Expr::If(_)
| Expr::Match(_)
+ | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
| Expr::While(_)
| Expr::Loop(_)
| Expr::ForLoop(_)
+ | Expr::TryBlock(_)
+ | Expr::Const(_) => false,
+
+ Expr::Array(_)
+ | Expr::Assign(_)
| Expr::Async(_)
- | Expr::TryBlock(_) => false,
+ | Expr::Await(_)
+ | Expr::Binary(_)
+ | Expr::Break(_)
+ | Expr::Call(_)
+ | Expr::Cast(_)
+ | Expr::Closure(_)
+ | Expr::Continue(_)
+ | Expr::Field(_)
+ | Expr::Group(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Macro(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Struct(_)
+ | Expr::Try(_)
+ | Expr::Tuple(_)
+ | Expr::Unary(_)
+ | Expr::Verbatim(_)
+ | Expr::Yield(_) => true,
+
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => true,
}
}
@@ -1097,25 +1028,53 @@ fn contains_exterior_struct_lit(expr: &Expr) -> bool {
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)
}
+ Expr::Array(_)
+ | Expr::Async(_)
+ | Expr::Block(_)
+ | Expr::Break(_)
+ | Expr::Call(_)
+ | Expr::Closure(_)
+ | Expr::Const(_)
+ | Expr::Continue(_)
+ | Expr::ForLoop(_)
+ | Expr::Group(_)
+ | Expr::If(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Loop(_)
+ | Expr::Macro(_)
+ | Expr::Match(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Try(_)
+ | Expr::TryBlock(_)
+ | Expr::Tuple(_)
+ | Expr::Unsafe(_)
+ | Expr::Verbatim(_)
+ | Expr::While(_)
+ | Expr::Yield(_) => false,
+
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => false,
}
}
@@ -1127,15 +1086,17 @@ fn needs_newline_if_wrap(expr: &Expr) -> bool {
| Expr::Block(_)
| Expr::Break(ExprBreak { expr: None, .. })
| Expr::Closure(_)
+ | Expr::Const(_)
| Expr::Continue(_)
| Expr::ForLoop(_)
| Expr::If(_)
+ | Expr::Infer(_)
| Expr::Lit(_)
| Expr::Loop(_)
| Expr::Macro(_)
| Expr::Match(_)
| Expr::Path(_)
- | Expr::Range(ExprRange { to: None, .. })
+ | Expr::Range(ExprRange { end: None, .. })
| Expr::Repeat(_)
| Expr::Return(ExprReturn { expr: None, .. })
| Expr::Struct(_)
@@ -1147,22 +1108,19 @@ fn needs_newline_if_wrap(expr: &Expr) -> bool {
| 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::MethodCall(_) => true,
- Expr::Box(ExprBox { expr: e, .. })
- | Expr::Break(ExprBreak { expr: Some(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::Range(ExprRange { end: Some(e), .. })
| Expr::Reference(ExprReference { expr: e, .. })
| Expr::Return(ExprReturn { expr: Some(e), .. })
| Expr::Try(ExprTry { expr: e, .. })
@@ -1176,16 +1134,12 @@ fn needs_newline_if_wrap(expr: &Expr) -> bool {
fn is_short_ident(expr: &Expr) -> bool {
if let Expr::Path(expr) = expr {
- if expr.attrs.is_empty()
+ return 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;
- }
- }
+ && expr
+ .path
+ .get_ident()
+ .map_or(false, |ident| ident.to_string().len() as isize <= INDENT);
}
false
}
@@ -1196,10 +1150,44 @@ fn is_blocklike(expr: &Expr) -> bool {
| Expr::Async(ExprAsync { attrs, .. })
| Expr::Block(ExprBlock { attrs, .. })
| Expr::Closure(ExprClosure { attrs, .. })
+ | Expr::Const(ExprConst { attrs, .. })
| Expr::Struct(ExprStruct { attrs, .. })
| Expr::TryBlock(ExprTryBlock { attrs, .. })
| Expr::Tuple(ExprTuple { attrs, .. })
| Expr::Unsafe(ExprUnsafe { attrs, .. }) => !attr::has_outer(attrs),
+
+ Expr::Assign(_)
+ | Expr::Await(_)
+ | Expr::Binary(_)
+ | Expr::Break(_)
+ | Expr::Call(_)
+ | Expr::Cast(_)
+ | Expr::Continue(_)
+ | Expr::Field(_)
+ | Expr::ForLoop(_)
+ | Expr::Group(_)
+ | Expr::If(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Loop(_)
+ | Expr::Macro(_)
+ | Expr::Match(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Try(_)
+ | Expr::Unary(_)
+ | Expr::Verbatim(_)
+ | Expr::While(_)
+ | Expr::Yield(_) => false,
+
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => false,
}
}
diff --git a/src/generics.rs b/src/generics.rs
index ede53de..35da0b2 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -1,11 +1,13 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
use crate::INDENT;
+use proc_macro2::TokenStream;
use std::ptr;
use syn::{
- BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
- PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound,
- WhereClause, WherePredicate,
+ BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
+ PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
+ WherePredicate,
};
impl Printer {
@@ -20,9 +22,6 @@ impl Printer {
// Print lifetimes before types and consts, regardless of their
// order in self.params.
- //
- // TODO: ordering rules for const parameters vs type parameters have
- // not been settled yet. https://github.com/rust-lang/rust/issues/44580
#[derive(Ord, PartialOrd, Eq, PartialEq)]
enum Group {
First,
@@ -52,26 +51,26 @@ impl Printer {
fn generic_param(&mut self, generic_param: &GenericParam) {
match generic_param {
GenericParam::Type(type_param) => self.type_param(type_param),
- GenericParam::Lifetime(lifetime_def) => self.lifetime_def(lifetime_def),
+ GenericParam::Lifetime(lifetime_param) => self.lifetime_param(lifetime_param),
GenericParam::Const(const_param) => self.const_param(const_param),
}
}
pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) {
self.word("for<");
- for lifetime_def in bound_lifetimes.lifetimes.iter().delimited() {
- self.lifetime_def(&lifetime_def);
- if !lifetime_def.is_last {
+ for param in bound_lifetimes.lifetimes.iter().delimited() {
+ self.generic_param(&param);
+ if !param.is_last {
self.word(", ");
}
}
self.word("> ");
}
- fn lifetime_def(&mut self, lifetime_def: &LifetimeDef) {
- self.outer_attrs(&lifetime_def.attrs);
- self.lifetime(&lifetime_def.lifetime);
- for lifetime in lifetime_def.bounds.iter().delimited() {
+ fn lifetime_param(&mut self, lifetime_param: &LifetimeParam) {
+ self.outer_attrs(&lifetime_param.attrs);
+ self.lifetime(&lifetime_param.lifetime);
+ for lifetime in lifetime_param.bounds.iter().delimited() {
if lifetime.is_first {
self.word(": ");
} else {
@@ -104,31 +103,33 @@ impl Printer {
pub fn type_param_bound(&mut self, type_param_bound: &TypeParamBound) {
match type_param_bound {
- TypeParamBound::Trait(trait_bound) => self.trait_bound(trait_bound),
+ TypeParamBound::Trait(trait_bound) => {
+ let tilde_const = false;
+ self.trait_bound(trait_bound, tilde_const);
+ }
TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime),
+ TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound),
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown TypeParamBound"),
}
}
- fn trait_bound(&mut self, trait_bound: &TraitBound) {
+ fn trait_bound(&mut self, trait_bound: &TraitBound, tilde_const: bool) {
if trait_bound.paren_token.is_some() {
self.word("(");
}
- let skip = match trait_bound.path.segments.first() {
- Some(segment) if segment.ident == "const" => {
- self.word("~const ");
- 1
- }
- _ => 0,
- };
+ if tilde_const {
+ self.word("~const ");
+ }
self.trait_bound_modifier(&trait_bound.modifier);
if let Some(bound_lifetimes) = &trait_bound.lifetimes {
self.bound_lifetimes(bound_lifetimes);
}
- for segment in trait_bound.path.segments.iter().skip(skip).delimited() {
+ for segment in trait_bound.path.segments.iter().delimited() {
if !segment.is_first || trait_bound.path.leading_colon.is_some() {
self.word("::");
}
- self.path_segment(&segment);
+ self.path_segment(&segment, PathKind::Type);
}
if trait_bound.paren_token.is_some() {
self.word(")");
@@ -142,6 +143,49 @@ impl Printer {
}
}
+ #[cfg(not(feature = "verbatim"))]
+ fn type_param_bound_verbatim(&mut self, bound: &TokenStream) {
+ unimplemented!("TypeParamBound::Verbatim `{}`", bound);
+ }
+
+ #[cfg(feature = "verbatim")]
+ fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) {
+ use syn::parse::{Parse, ParseStream, Result};
+ use syn::{parenthesized, token, Token};
+
+ enum TypeParamBoundVerbatim {
+ TildeConst(TraitBound),
+ }
+
+ impl Parse for TypeParamBoundVerbatim {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ let (paren_token, content) = if input.peek(token::Paren) {
+ (Some(parenthesized!(content in input)), &content)
+ } else {
+ (None, input)
+ };
+ content.parse::<Token![~]>()?;
+ content.parse::<Token![const]>()?;
+ let mut bound: TraitBound = content.parse()?;
+ bound.paren_token = paren_token;
+ Ok(TypeParamBoundVerbatim::TildeConst(bound))
+ }
+ }
+
+ let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) {
+ Ok(bound) => bound,
+ Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens),
+ };
+
+ match bound {
+ TypeParamBoundVerbatim::TildeConst(trait_bound) => {
+ let tilde_const = true;
+ self.trait_bound(&trait_bound, tilde_const);
+ }
+ }
+ }
+
fn const_param(&mut self, const_param: &ConstParam) {
self.outer_attrs(&const_param.attrs);
self.word("const ");
@@ -235,7 +279,8 @@ impl Printer {
match predicate {
WherePredicate::Type(predicate) => self.predicate_type(predicate),
WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate),
- WherePredicate::Eq(predicate) => self.predicate_eq(predicate),
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown WherePredicate"),
}
}
@@ -277,10 +322,4 @@ impl Printer {
}
self.end();
}
-
- fn predicate_eq(&mut self, predicate: &PredicateEq) {
- self.ty(&predicate.lhs_ty);
- self.word(" = ");
- self.ty(&predicate.rhs_ty);
- }
}
diff --git a/src/item.rs b/src/item.rs
index 62252f1..88d0c04 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1,14 +1,15 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic,
- ForeignItemType, ImplItem, ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, Item,
- ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2,
- ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Pat,
- Receiver, Signature, Stmt, TraitItem, TraitItemConst, TraitItemMacro, TraitItemMethod,
- TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree,
+ ForeignItemType, ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, Item,
+ ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,
+ ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,
+ Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,
+ TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,
};
impl Printer {
@@ -21,7 +22,6 @@ impl Printer {
Item::ForeignMod(item) => self.item_foreign_mod(item),
Item::Impl(item) => self.item_impl(item),
Item::Macro(item) => self.item_macro(item),
- Item::Macro2(item) => self.item_macro2(item),
Item::Mod(item) => self.item_mod(item),
Item::Static(item) => self.item_static(item),
Item::Struct(item) => self.item_struct(item),
@@ -42,6 +42,7 @@ impl Printer {
self.visibility(&item.vis);
self.word("const ");
self.ident(&item.ident);
+ self.generics(&item.generics);
self.word(": ");
self.ty(&item.ty);
self.word(" = ");
@@ -107,6 +108,9 @@ impl Printer {
fn item_foreign_mod(&mut self, item: &ItemForeignMod) {
self.outer_attrs(&item.attrs);
self.cbox(INDENT);
+ if item.unsafety.is_some() {
+ self.word("unsafe ");
+ }
self.abi(&item.abi);
self.word("{");
self.hardbreak_if_nonempty();
@@ -139,7 +143,7 @@ impl Printer {
if negative_polarity.is_some() {
self.word("!");
}
- self.path(path);
+ self.path(path, PathKind::Type);
self.space();
self.word("for ");
}
@@ -160,19 +164,18 @@ impl Printer {
fn item_macro(&mut self, item: &ItemMacro) {
self.outer_attrs(&item.attrs);
- self.mac(&item.mac, item.ident.as_ref());
- self.mac_semi_if_needed(&item.mac.delimiter);
+ let semicolon = true;
+ self.mac(&item.mac, item.ident.as_ref(), semicolon);
self.hardbreak();
}
- fn item_macro2(&mut self, item: &ItemMacro2) {
- unimplemented!("Item::Macro2 `macro {} {}`", item.ident, item.rules);
- }
-
fn item_mod(&mut self, item: &ItemMod) {
self.outer_attrs(&item.attrs);
self.cbox(INDENT);
self.visibility(&item.vis);
+ if item.unsafety.is_some() {
+ self.word("unsafe ");
+ }
self.word("mod ");
self.ident(&item.ident);
if let Some((_brace, items)) = &item.content {
@@ -197,9 +200,7 @@ impl Printer {
self.cbox(0);
self.visibility(&item.vis);
self.word("static ");
- if item.mutability.is_some() {
- self.word("mut ");
- }
+ self.static_mutability(&item.mutability);
self.ident(&item.ident);
self.word(": ");
self.ty(&item.ty);
@@ -362,25 +363,202 @@ impl Printer {
#[cfg(feature = "verbatim")]
fn item_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
- use syn::{Attribute, Token};
+ use syn::punctuated::Punctuated;
+ use syn::{
+ braced, parenthesized, token, Attribute, Generics, Ident, Lifetime, Token, Visibility,
+ };
+ use verbatim::{
+ FlexibleItemConst, FlexibleItemFn, FlexibleItemStatic, FlexibleItemType,
+ WhereClauseLocation,
+ };
enum ItemVerbatim {
Empty,
- UnsafeForeignMod(ItemForeignMod),
+ ConstFlexible(FlexibleItemConst),
+ FnFlexible(FlexibleItemFn),
+ ImplFlexible(ImplFlexible),
+ Macro2(Macro2),
+ StaticFlexible(FlexibleItemStatic),
+ TypeFlexible(FlexibleItemType),
+ UseBrace(UseBrace),
+ }
+
+ struct ImplFlexible {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ defaultness: bool,
+ unsafety: bool,
+ generics: Generics,
+ constness: ImplConstness,
+ negative_impl: bool,
+ trait_: Option<Type>,
+ self_ty: Type,
+ items: Vec<ImplItem>,
+ }
+
+ enum ImplConstness {
+ None,
+ MaybeConst,
+ Const,
+ }
+
+ struct Macro2 {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ ident: Ident,
+ args: Option<TokenStream>,
+ body: TokenStream,
+ }
+
+ struct UseBrace {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ trees: Punctuated<RootUseTree, Token![,]>,
+ }
+
+ struct RootUseTree {
+ leading_colon: Option<Token![::]>,
+ inner: UseTree,
+ }
+
+ impl Parse for ImplConstness {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.parse::<Option<Token![?]>>()?.is_some() {
+ input.parse::<Token![const]>()?;
+ Ok(ImplConstness::MaybeConst)
+ } else if input.parse::<Option<Token![const]>>()?.is_some() {
+ Ok(ImplConstness::Const)
+ } else {
+ Ok(ImplConstness::None)
+ }
+ }
+ }
+
+ impl Parse for RootUseTree {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(RootUseTree {
+ leading_colon: input.parse()?,
+ inner: input.parse()?,
+ })
+ }
}
impl Parse for ItemVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
if input.is_empty() {
- Ok(ItemVerbatim::Empty)
- } else {
- let attrs = input.call(Attribute::parse_outer)?;
- input.parse::<Token![unsafe]>()?;
- let module: ItemForeignMod = input.parse()?;
- Ok(ItemVerbatim::UnsafeForeignMod(ItemForeignMod {
+ return Ok(ItemVerbatim::Empty);
+ }
+
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) {
+ let defaultness = false;
+ let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?;
+ Ok(ItemVerbatim::ConstFlexible(flexible_item))
+ } else if input.peek(Token![const])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe]) && !input.peek2(Token![impl])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ let defaultness = false;
+ let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?;
+ Ok(ItemVerbatim::FnFlexible(flexible_item))
+ } else if lookahead.peek(Token![default])
+ || input.peek(Token![unsafe])
+ || lookahead.peek(Token![impl])
+ {
+ let defaultness = input.parse::<Option<Token![default]>>()?.is_some();
+ let unsafety = input.parse::<Option<Token![unsafe]>>()?.is_some();
+ input.parse::<Token![impl]>()?;
+ let has_generics = input.peek(Token![<])
+ && (input.peek2(Token![>])
+ || input.peek2(Token![#])
+ || (input.peek2(Ident) || input.peek2(Lifetime))
+ && (input.peek3(Token![:])
+ || input.peek3(Token![,])
+ || input.peek3(Token![>])
+ || input.peek3(Token![=]))
+ || input.peek2(Token![const]));
+ let mut generics: Generics = if has_generics {
+ input.parse()?
+ } else {
+ Generics::default()
+ };
+ let constness: ImplConstness = input.parse()?;
+ let negative_impl =
+ !input.peek2(token::Brace) && input.parse::<Option<Token![!]>>()?.is_some();
+ let first_ty: Type = input.parse()?;
+ let (trait_, self_ty) = if input.parse::<Option<Token![for]>>()?.is_some() {
+ (Some(first_ty), input.parse()?)
+ } else {
+ (None, first_ty)
+ };
+ generics.where_clause = input.parse()?;
+ let content;
+ braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ attrs.extend(inner_attrs);
+ let mut items = Vec::new();
+ while !content.is_empty() {
+ items.push(content.parse()?);
+ }
+ Ok(ItemVerbatim::ImplFlexible(ImplFlexible {
+ attrs,
+ vis,
+ defaultness,
+ unsafety,
+ generics,
+ constness,
+ negative_impl,
+ trait_,
+ self_ty,
+ items,
+ }))
+ } else if lookahead.peek(Token![macro]) {
+ input.parse::<Token![macro]>()?;
+ let ident: Ident = input.parse()?;
+ let args = if input.peek(token::Paren) {
+ let paren_content;
+ parenthesized!(paren_content in input);
+ Some(paren_content.parse::<TokenStream>()?)
+ } else {
+ None
+ };
+ let brace_content;
+ braced!(brace_content in input);
+ let body: TokenStream = brace_content.parse()?;
+ Ok(ItemVerbatim::Macro2(Macro2 {
attrs,
- ..module
+ vis,
+ ident,
+ args,
+ body,
}))
+ } else if lookahead.peek(Token![static]) {
+ let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?;
+ Ok(ItemVerbatim::StaticFlexible(flexible_item))
+ } else if lookahead.peek(Token![type]) {
+ let defaultness = false;
+ let flexible_item = FlexibleItemType::parse(
+ attrs,
+ vis,
+ defaultness,
+ input,
+ WhereClauseLocation::BeforeEq,
+ )?;
+ Ok(ItemVerbatim::TypeFlexible(flexible_item))
+ } else if lookahead.peek(Token![use]) {
+ input.parse::<Token![use]>()?;
+ let content;
+ braced!(content in input);
+ let trees = content.parse_terminated(RootUseTree::parse, Token![,])?;
+ input.parse::<Token![;]>()?;
+ Ok(ItemVerbatim::UseBrace(UseBrace { attrs, vis, trees }))
+ } else {
+ Err(lookahead.error())
}
}
}
@@ -391,25 +569,136 @@ impl Printer {
};
match item {
- ItemVerbatim::Empty => {}
- ItemVerbatim::UnsafeForeignMod(item) => {
+ ItemVerbatim::Empty => {
+ self.hardbreak();
+ }
+ ItemVerbatim::ConstFlexible(item) => {
+ self.flexible_item_const(&item);
+ }
+ ItemVerbatim::FnFlexible(item) => {
+ self.flexible_item_fn(&item);
+ }
+ ItemVerbatim::ImplFlexible(item) => {
self.outer_attrs(&item.attrs);
self.cbox(INDENT);
- self.word("unsafe ");
- self.abi(&item.abi);
+ self.ibox(-INDENT);
+ self.cbox(INDENT);
+ self.visibility(&item.vis);
+ if item.defaultness {
+ self.word("default ");
+ }
+ if item.unsafety {
+ self.word("unsafe ");
+ }
+ self.word("impl");
+ self.generics(&item.generics);
+ self.end();
+ self.nbsp();
+ match item.constness {
+ ImplConstness::None => {}
+ ImplConstness::MaybeConst => self.word("?const "),
+ ImplConstness::Const => self.word("const "),
+ }
+ if item.negative_impl {
+ self.word("!");
+ }
+ if let Some(trait_) = &item.trait_ {
+ self.ty(trait_);
+ self.space();
+ self.word("for ");
+ }
+ self.ty(&item.self_ty);
+ self.end();
+ self.where_clause_for_body(&item.generics.where_clause);
self.word("{");
self.hardbreak_if_nonempty();
self.inner_attrs(&item.attrs);
- for foreign_item in &item.items {
- self.foreign_item(foreign_item);
+ for impl_item in &item.items {
+ self.impl_item(impl_item);
}
self.offset(-INDENT);
self.end();
self.word("}");
+ self.hardbreak();
+ }
+ ItemVerbatim::Macro2(item) => {
+ self.outer_attrs(&item.attrs);
+ self.visibility(&item.vis);
+ self.word("macro ");
+ self.ident(&item.ident);
+ if let Some(args) = &item.args {
+ self.word("(");
+ self.cbox(INDENT);
+ self.zerobreak();
+ self.ibox(0);
+ self.macro_rules_tokens(args.clone(), true);
+ self.end();
+ self.zerobreak();
+ self.offset(-INDENT);
+ self.end();
+ self.word(")");
+ }
+ self.word(" {");
+ if !item.body.is_empty() {
+ self.neverbreak();
+ self.cbox(INDENT);
+ self.hardbreak();
+ self.ibox(0);
+ self.macro_rules_tokens(item.body.clone(), false);
+ self.end();
+ self.hardbreak();
+ self.offset(-INDENT);
+ self.end();
+ }
+ self.word("}");
+ self.hardbreak();
+ }
+ ItemVerbatim::StaticFlexible(item) => {
+ self.flexible_item_static(&item);
+ }
+ ItemVerbatim::TypeFlexible(item) => {
+ self.flexible_item_type(&item);
+ }
+ ItemVerbatim::UseBrace(item) => {
+ self.outer_attrs(&item.attrs);
+ self.visibility(&item.vis);
+ self.word("use ");
+ if item.trees.len() == 1 {
+ self.word("::");
+ self.use_tree(&item.trees[0].inner);
+ } else {
+ self.cbox(INDENT);
+ self.word("{");
+ self.zerobreak();
+ self.ibox(0);
+ for use_tree in item.trees.iter().delimited() {
+ if use_tree.leading_colon.is_some() {
+ self.word("::");
+ }
+ self.use_tree(&use_tree.inner);
+ if !use_tree.is_last {
+ self.word(",");
+ let mut use_tree = &use_tree.inner;
+ while let UseTree::Path(use_path) = use_tree {
+ use_tree = &use_path.tree;
+ }
+ if let UseTree::Group(_) = use_tree {
+ self.hardbreak();
+ } else {
+ self.space();
+ }
+ }
+ }
+ self.end();
+ self.trailing_comma(true);
+ self.offset(-INDENT);
+ self.word("}");
+ self.end();
+ }
+ self.word(";");
+ self.hardbreak();
}
}
-
- self.hardbreak();
}
fn use_tree(&mut self, use_tree: &UseTree) {
@@ -503,9 +792,7 @@ impl Printer {
self.cbox(0);
self.visibility(&foreign_item.vis);
self.word("static ");
- if foreign_item.mutability.is_some() {
- self.word("mut ");
- }
+ self.static_mutability(&foreign_item.mutability);
self.ident(&foreign_item.ident);
self.word(": ");
self.ty(&foreign_item.ty);
@@ -520,6 +807,7 @@ impl Printer {
self.visibility(&foreign_item.vis);
self.word("type ");
self.ident(&foreign_item.ident);
+ self.generics(&foreign_item.generics);
self.word(";");
self.end();
self.hardbreak();
@@ -527,8 +815,8 @@ impl Printer {
fn foreign_item_macro(&mut self, foreign_item: &ForeignItemMacro) {
self.outer_attrs(&foreign_item.attrs);
- self.mac(&foreign_item.mac, None);
- self.mac_semi_if_needed(&foreign_item.mac.delimiter);
+ let semicolon = true;
+ self.mac(&foreign_item.mac, None, semicolon);
self.hardbreak();
}
@@ -543,14 +831,50 @@ impl Printer {
#[cfg(feature = "verbatim")]
fn foreign_item_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
+ use syn::{Attribute, Token, Visibility};
+ use verbatim::{FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, WhereClauseLocation};
enum ForeignItemVerbatim {
- TypeAlias(ItemType),
+ Empty,
+ FnFlexible(FlexibleItemFn),
+ StaticFlexible(FlexibleItemStatic),
+ TypeFlexible(FlexibleItemType),
}
impl Parse for ForeignItemVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
- input.parse().map(ForeignItemVerbatim::TypeAlias)
+ if input.is_empty() {
+ return Ok(ForeignItemVerbatim::Empty);
+ }
+
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let defaultness = false;
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![const])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?;
+ Ok(ForeignItemVerbatim::FnFlexible(flexible_item))
+ } else if lookahead.peek(Token![static]) {
+ let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?;
+ Ok(ForeignItemVerbatim::StaticFlexible(flexible_item))
+ } else if lookahead.peek(Token![type]) {
+ let flexible_item = FlexibleItemType::parse(
+ attrs,
+ vis,
+ defaultness,
+ input,
+ WhereClauseLocation::Both,
+ )?;
+ Ok(ForeignItemVerbatim::TypeFlexible(flexible_item))
+ } else {
+ Err(lookahead.error())
+ }
}
}
@@ -560,14 +884,25 @@ impl Printer {
};
match foreign_item {
- ForeignItemVerbatim::TypeAlias(item) => self.item_type(&item),
+ ForeignItemVerbatim::Empty => {
+ self.hardbreak();
+ }
+ ForeignItemVerbatim::FnFlexible(foreign_item) => {
+ self.flexible_item_fn(&foreign_item);
+ }
+ ForeignItemVerbatim::StaticFlexible(foreign_item) => {
+ self.flexible_item_static(&foreign_item);
+ }
+ ForeignItemVerbatim::TypeFlexible(foreign_item) => {
+ self.flexible_item_type(&foreign_item);
+ }
}
}
fn trait_item(&mut self, trait_item: &TraitItem) {
match trait_item {
TraitItem::Const(item) => self.trait_item_const(item),
- TraitItem::Method(item) => self.trait_item_method(item),
+ TraitItem::Fn(item) => self.trait_item_fn(item),
TraitItem::Type(item) => self.trait_item_type(item),
TraitItem::Macro(item) => self.trait_item_macro(item),
TraitItem::Verbatim(item) => self.trait_item_verbatim(item),
@@ -581,6 +916,7 @@ impl Printer {
self.cbox(0);
self.word("const ");
self.ident(&trait_item.ident);
+ self.generics(&trait_item.generics);
self.word(": ");
self.ty(&trait_item.ty);
if let Some((_eq_token, default)) = &trait_item.default {
@@ -593,7 +929,7 @@ impl Printer {
self.hardbreak();
}
- fn trait_item_method(&mut self, trait_item: &TraitItemMethod) {
+ fn trait_item_fn(&mut self, trait_item: &TraitItemFn) {
self.outer_attrs(&trait_item.attrs);
self.cbox(INDENT);
self.signature(&trait_item.sig);
@@ -633,7 +969,9 @@ impl Printer {
if let Some((_eq_token, default)) = &trait_item.default {
self.word(" = ");
self.neverbreak();
+ self.ibox(-INDENT);
self.ty(default);
+ self.end();
}
self.where_clause_oneline_semi(&trait_item.generics.where_clause);
self.end();
@@ -642,11 +980,12 @@ impl Printer {
fn trait_item_macro(&mut self, trait_item: &TraitItemMacro) {
self.outer_attrs(&trait_item.attrs);
- self.mac(&trait_item.mac, None);
- self.mac_semi_if_needed(&trait_item.mac.delimiter);
+ let semicolon = true;
+ self.mac(&trait_item.mac, None, semicolon);
self.hardbreak();
}
+ #[cfg(not(feature = "verbatim"))]
fn trait_item_verbatim(&mut self, trait_item: &TokenStream) {
if !trait_item.is_empty() {
unimplemented!("TraitItem::Verbatim `{}`", trait_item);
@@ -654,10 +993,91 @@ impl Printer {
self.hardbreak();
}
+ #[cfg(feature = "verbatim")]
+ fn trait_item_verbatim(&mut self, tokens: &TokenStream) {
+ use syn::parse::{Parse, ParseStream, Result};
+ use syn::{Attribute, Token, Visibility};
+ use verbatim::{FlexibleItemType, WhereClauseLocation};
+
+ enum TraitItemVerbatim {
+ Empty,
+ TypeFlexible(FlexibleItemType),
+ PubOrDefault(PubOrDefaultTraitItem),
+ }
+
+ struct PubOrDefaultTraitItem {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ defaultness: bool,
+ trait_item: TraitItem,
+ }
+
+ impl Parse for TraitItemVerbatim {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.is_empty() {
+ return Ok(TraitItemVerbatim::Empty);
+ }
+
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let defaultness = input.parse::<Option<Token![default]>>()?.is_some();
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![type]) {
+ let flexible_item = FlexibleItemType::parse(
+ attrs,
+ vis,
+ defaultness,
+ input,
+ WhereClauseLocation::AfterEq,
+ )?;
+ Ok(TraitItemVerbatim::TypeFlexible(flexible_item))
+ } else if (lookahead.peek(Token![const])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn]))
+ && (!matches!(vis, Visibility::Inherited) || defaultness)
+ {
+ Ok(TraitItemVerbatim::PubOrDefault(PubOrDefaultTraitItem {
+ attrs,
+ vis,
+ defaultness,
+ trait_item: input.parse()?,
+ }))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ let impl_item: TraitItemVerbatim = match syn::parse2(tokens.clone()) {
+ Ok(impl_item) => impl_item,
+ Err(_) => unimplemented!("TraitItem::Verbatim `{}`", tokens),
+ };
+
+ match impl_item {
+ TraitItemVerbatim::Empty => {
+ self.hardbreak();
+ }
+ TraitItemVerbatim::TypeFlexible(trait_item) => {
+ self.flexible_item_type(&trait_item);
+ }
+ TraitItemVerbatim::PubOrDefault(trait_item) => {
+ self.outer_attrs(&trait_item.attrs);
+ self.visibility(&trait_item.vis);
+ if trait_item.defaultness {
+ self.word("default ");
+ }
+ self.trait_item(&trait_item.trait_item);
+ }
+ }
+ }
+
fn impl_item(&mut self, impl_item: &ImplItem) {
match impl_item {
ImplItem::Const(item) => self.impl_item_const(item),
- ImplItem::Method(item) => self.impl_item_method(item),
+ ImplItem::Fn(item) => self.impl_item_fn(item),
ImplItem::Type(item) => self.impl_item_type(item),
ImplItem::Macro(item) => self.impl_item_macro(item),
ImplItem::Verbatim(item) => self.impl_item_verbatim(item),
@@ -675,6 +1095,7 @@ impl Printer {
}
self.word("const ");
self.ident(&impl_item.ident);
+ self.generics(&impl_item.generics);
self.word(": ");
self.ty(&impl_item.ty);
self.word(" = ");
@@ -685,7 +1106,7 @@ impl Printer {
self.hardbreak();
}
- fn impl_item_method(&mut self, impl_item: &ImplItemMethod) {
+ fn impl_item_fn(&mut self, impl_item: &ImplItemFn) {
self.outer_attrs(&impl_item.attrs);
self.cbox(INDENT);
self.visibility(&impl_item.vis);
@@ -693,16 +1114,6 @@ impl Printer {
self.word("default ");
}
self.signature(&impl_item.sig);
- if impl_item.block.stmts.len() == 1 {
- if let Stmt::Item(Item::Verbatim(verbatim)) = &impl_item.block.stmts[0] {
- if verbatim.to_string() == ";" {
- self.where_clause_semi(&impl_item.sig.generics.where_clause);
- self.end();
- self.hardbreak();
- return;
- }
- }
- }
self.where_clause_for_body(&impl_item.sig.generics.where_clause);
self.word("{");
self.hardbreak_if_nonempty();
@@ -738,11 +1149,12 @@ impl Printer {
fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) {
self.outer_attrs(&impl_item.attrs);
- self.mac(&impl_item.mac, None);
- self.mac_semi_if_needed(&impl_item.mac.delimiter);
+ let semicolon = true;
+ self.mac(&impl_item.mac, None, semicolon);
self.hardbreak();
}
+ #[cfg(not(feature = "verbatim"))]
fn impl_item_verbatim(&mut self, impl_item: &TokenStream) {
if !impl_item.is_empty() {
unimplemented!("ImplItem::Verbatim `{}`", impl_item);
@@ -750,29 +1162,73 @@ impl Printer {
self.hardbreak();
}
- fn maybe_variadic(&mut self, arg: &FnArg) -> bool {
- let pat_type = match arg {
- FnArg::Typed(pat_type) => pat_type,
- FnArg::Receiver(receiver) => {
- self.receiver(receiver);
- return false;
+ #[cfg(feature = "verbatim")]
+ fn impl_item_verbatim(&mut self, tokens: &TokenStream) {
+ use syn::parse::{Parse, ParseStream, Result};
+ use syn::{Attribute, Ident, Token, Visibility};
+ use verbatim::{FlexibleItemConst, FlexibleItemFn, FlexibleItemType, WhereClauseLocation};
+
+ enum ImplItemVerbatim {
+ Empty,
+ ConstFlexible(FlexibleItemConst),
+ FnFlexible(FlexibleItemFn),
+ TypeFlexible(FlexibleItemType),
+ }
+
+ impl Parse for ImplItemVerbatim {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.is_empty() {
+ return Ok(ImplItemVerbatim::Empty);
+ }
+
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let defaultness = input.parse::<Option<Token![default]>>()?.is_some();
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) {
+ let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?;
+ Ok(ImplItemVerbatim::ConstFlexible(flexible_item))
+ } else if input.peek(Token![const])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?;
+ Ok(ImplItemVerbatim::FnFlexible(flexible_item))
+ } else if lookahead.peek(Token![type]) {
+ let flexible_item = FlexibleItemType::parse(
+ attrs,
+ vis,
+ defaultness,
+ input,
+ WhereClauseLocation::AfterEq,
+ )?;
+ Ok(ImplItemVerbatim::TypeFlexible(flexible_item))
+ } else {
+ Err(lookahead.error())
+ }
}
+ }
+
+ let impl_item: ImplItemVerbatim = match syn::parse2(tokens.clone()) {
+ Ok(impl_item) => impl_item,
+ Err(_) => unimplemented!("ImplItem::Verbatim `{}`", tokens),
};
- match pat_type.ty.as_ref() {
- Type::Verbatim(ty) if ty.to_string() == "..." => {
- match pat_type.pat.as_ref() {
- Pat::Verbatim(pat) if pat.to_string() == "..." => {
- self.outer_attrs(&pat_type.attrs);
- self.word("...");
- }
- _ => self.pat_type(pat_type),
- }
- true
+ match impl_item {
+ ImplItemVerbatim::Empty => {
+ self.hardbreak();
+ }
+ ImplItemVerbatim::ConstFlexible(impl_item) => {
+ self.flexible_item_const(&impl_item);
}
- _ => {
- self.pat_type(pat_type);
- false
+ ImplItemVerbatim::FnFlexible(impl_item) => {
+ self.flexible_item_fn(&impl_item);
+ }
+ ImplItemVerbatim::TypeFlexible(impl_item) => {
+ self.flexible_item_type(&impl_item);
}
}
}
@@ -797,18 +1253,13 @@ impl Printer {
self.neverbreak();
self.cbox(0);
self.zerobreak();
- let mut last_is_variadic = false;
for input in signature.inputs.iter().delimited() {
- last_is_variadic = self.maybe_variadic(&input);
- if last_is_variadic {
- self.zerobreak();
- } else {
- let is_last = input.is_last && signature.variadic.is_none();
- self.trailing_comma(is_last);
- }
+ self.fn_arg(&input);
+ let is_last = input.is_last && signature.variadic.is_none();
+ self.trailing_comma(is_last);
}
- if signature.variadic.is_some() && !last_is_variadic {
- self.word("...");
+ if let Some(variadic) = &signature.variadic {
+ self.variadic(variadic);
self.zerobreak();
}
self.offset(-INDENT);
@@ -819,6 +1270,13 @@ impl Printer {
self.end();
}
+ fn fn_arg(&mut self, fn_arg: &FnArg) {
+ match fn_arg {
+ FnArg::Receiver(receiver) => self.receiver(receiver),
+ FnArg::Typed(pat_type) => self.pat_type(pat_type),
+ }
+ }
+
fn receiver(&mut self, receiver: &Receiver) {
self.outer_attrs(&receiver.attrs);
if let Some((_ampersand, lifetime)) = &receiver.reference {
@@ -832,5 +1290,357 @@ impl Printer {
self.word("mut ");
}
self.word("self");
+ if receiver.colon_token.is_some() {
+ self.word(": ");
+ self.ty(&receiver.ty);
+ } else {
+ let consistent = match (&receiver.reference, &receiver.mutability, &*receiver.ty) {
+ (Some(_), mutability, Type::Reference(ty)) => {
+ mutability.is_some() == ty.mutability.is_some()
+ && match &*ty.elem {
+ Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"),
+ _ => false,
+ }
+ }
+ (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"),
+ _ => false,
+ };
+ if !consistent {
+ self.word(": ");
+ self.ty(&receiver.ty);
+ }
+ }
+ }
+
+ fn variadic(&mut self, variadic: &Variadic) {
+ self.outer_attrs(&variadic.attrs);
+ if let Some((pat, _colon)) = &variadic.pat {
+ self.pat(pat);
+ self.word(": ");
+ }
+ self.word("...");
+ }
+
+ fn static_mutability(&mut self, mutability: &StaticMutability) {
+ match mutability {
+ StaticMutability::Mut(_) => self.word("mut "),
+ StaticMutability::None => {}
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown StaticMutability"),
+ }
+ }
+}
+
+#[cfg(feature = "verbatim")]
+mod verbatim {
+ use crate::algorithm::Printer;
+ use crate::iter::IterDelimited;
+ use crate::INDENT;
+ use syn::ext::IdentExt;
+ use syn::parse::{ParseStream, Result};
+ use syn::{
+ braced, token, Attribute, Block, Expr, Generics, Ident, Signature, StaticMutability, Stmt,
+ Token, Type, TypeParamBound, Visibility, WhereClause,
+ };
+
+ pub struct FlexibleItemConst {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: bool,
+ pub ident: Ident,
+ pub ty: Type,
+ }
+
+ pub struct FlexibleItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: bool,
+ pub sig: Signature,
+ pub body: Option<Vec<Stmt>>,
+ }
+
+ pub struct FlexibleItemStatic {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub mutability: StaticMutability,
+ pub ident: Ident,
+ pub ty: Option<Type>,
+ pub expr: Option<Expr>,
+ }
+
+ pub struct FlexibleItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: bool,
+ pub ident: Ident,
+ pub generics: Generics,
+ pub bounds: Vec<TypeParamBound>,
+ pub definition: Option<Type>,
+ pub where_clause_after_eq: Option<WhereClause>,
+ }
+
+ pub enum WhereClauseLocation {
+ // type Ty<T> where T: 'static = T;
+ BeforeEq,
+ // type Ty<T> = T where T: 'static;
+ AfterEq,
+ // TODO: goes away once the migration period on rust-lang/rust#89122 is over
+ Both,
+ }
+
+ impl FlexibleItemConst {
+ pub fn parse(
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ defaultness: bool,
+ input: ParseStream,
+ ) -> Result<Self> {
+ input.parse::<Token![const]>()?;
+ let ident = input.call(Ident::parse_any)?;
+ input.parse::<Token![:]>()?;
+ let ty: Type = input.parse()?;
+ input.parse::<Token![;]>()?;
+
+ Ok(FlexibleItemConst {
+ attrs,
+ vis,
+ defaultness,
+ ident,
+ ty,
+ })
+ }
+ }
+
+ impl FlexibleItemFn {
+ pub fn parse(
+ mut attrs: Vec<Attribute>,
+ vis: Visibility,
+ defaultness: bool,
+ input: ParseStream,
+ ) -> Result<Self> {
+ let sig: Signature = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let body = if lookahead.peek(Token![;]) {
+ input.parse::<Token![;]>()?;
+ None
+ } else if lookahead.peek(token::Brace) {
+ let content;
+ braced!(content in input);
+ attrs.extend(content.call(Attribute::parse_inner)?);
+ Some(content.call(Block::parse_within)?)
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok(FlexibleItemFn {
+ attrs,
+ vis,
+ defaultness,
+ sig,
+ body,
+ })
+ }
+ }
+
+ impl FlexibleItemStatic {
+ pub fn parse(attrs: Vec<Attribute>, vis: Visibility, input: ParseStream) -> Result<Self> {
+ input.parse::<Token![static]>()?;
+ let mutability: StaticMutability = input.parse()?;
+ let ident = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let has_type = lookahead.peek(Token![:]);
+ let has_expr = lookahead.peek(Token![=]);
+ if !has_type && !has_expr {
+ return Err(lookahead.error());
+ }
+
+ let ty: Option<Type> = if has_type {
+ input.parse::<Token![:]>()?;
+ input.parse().map(Some)?
+ } else {
+ None
+ };
+
+ let expr: Option<Expr> = if input.parse::<Option<Token![=]>>()?.is_some() {
+ input.parse().map(Some)?
+ } else {
+ None
+ };
+
+ input.parse::<Token![;]>()?;
+
+ Ok(FlexibleItemStatic {
+ attrs,
+ vis,
+ mutability,
+ ident,
+ ty,
+ expr,
+ })
+ }
+ }
+
+ impl FlexibleItemType {
+ pub fn parse(
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ defaultness: bool,
+ input: ParseStream,
+ where_clause_location: WhereClauseLocation,
+ ) -> Result<Self> {
+ input.parse::<Token![type]>()?;
+ let ident: Ident = input.parse()?;
+ let mut generics: Generics = input.parse()?;
+
+ let mut bounds = Vec::new();
+ if input.parse::<Option<Token![:]>>()?.is_some() {
+ loop {
+ if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) {
+ break;
+ }
+ bounds.push(input.parse::<TypeParamBound>()?);
+ if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) {
+ break;
+ }
+ input.parse::<Token![+]>()?;
+ }
+ }
+
+ match where_clause_location {
+ WhereClauseLocation::BeforeEq | WhereClauseLocation::Both => {
+ generics.where_clause = input.parse()?;
+ }
+ WhereClauseLocation::AfterEq => {}
+ }
+
+ let definition = if input.parse::<Option<Token![=]>>()?.is_some() {
+ Some(input.parse()?)
+ } else {
+ None
+ };
+
+ let where_clause_after_eq = match where_clause_location {
+ WhereClauseLocation::AfterEq | WhereClauseLocation::Both
+ if generics.where_clause.is_none() =>
+ {
+ input.parse()?
+ }
+ _ => None,
+ };
+
+ input.parse::<Token![;]>()?;
+
+ Ok(FlexibleItemType {
+ attrs,
+ vis,
+ defaultness,
+ ident,
+ generics,
+ bounds,
+ definition,
+ where_clause_after_eq,
+ })
+ }
+ }
+
+ impl Printer {
+ pub fn flexible_item_const(&mut self, item: &FlexibleItemConst) {
+ self.outer_attrs(&item.attrs);
+ self.cbox(0);
+ self.visibility(&item.vis);
+ if item.defaultness {
+ self.word("default ");
+ }
+ self.word("const ");
+ self.ident(&item.ident);
+ self.word(": ");
+ self.ty(&item.ty);
+ self.word(";");
+ self.end();
+ self.hardbreak();
+ }
+
+ pub fn flexible_item_fn(&mut self, item: &FlexibleItemFn) {
+ self.outer_attrs(&item.attrs);
+ self.cbox(INDENT);
+ self.visibility(&item.vis);
+ if item.defaultness {
+ self.word("default ");
+ }
+ self.signature(&item.sig);
+ if let Some(body) = &item.body {
+ self.where_clause_for_body(&item.sig.generics.where_clause);
+ self.word("{");
+ self.hardbreak_if_nonempty();
+ self.inner_attrs(&item.attrs);
+ for stmt in body {
+ self.stmt(stmt);
+ }
+ self.offset(-INDENT);
+ self.end();
+ self.word("}");
+ } else {
+ self.where_clause_semi(&item.sig.generics.where_clause);
+ self.end();
+ }
+ self.hardbreak();
+ }
+
+ pub fn flexible_item_static(&mut self, item: &FlexibleItemStatic) {
+ self.outer_attrs(&item.attrs);
+ self.cbox(0);
+ self.visibility(&item.vis);
+ self.word("static ");
+ self.static_mutability(&item.mutability);
+ self.ident(&item.ident);
+ if let Some(ty) = &item.ty {
+ self.word(": ");
+ self.ty(ty);
+ }
+ if let Some(expr) = &item.expr {
+ self.word(" = ");
+ self.neverbreak();
+ self.expr(expr);
+ }
+ self.word(";");
+ self.end();
+ self.hardbreak();
+ }
+
+ pub fn flexible_item_type(&mut self, item: &FlexibleItemType) {
+ self.outer_attrs(&item.attrs);
+ self.cbox(INDENT);
+ self.visibility(&item.vis);
+ if item.defaultness {
+ self.word("default ");
+ }
+ self.word("type ");
+ self.ident(&item.ident);
+ self.generics(&item.generics);
+ for bound in item.bounds.iter().delimited() {
+ if bound.is_first {
+ self.word(": ");
+ } else {
+ self.space();
+ self.word("+ ");
+ }
+ self.type_param_bound(&bound);
+ }
+ if let Some(definition) = &item.definition {
+ self.where_clause_oneline(&item.generics.where_clause);
+ self.word("= ");
+ self.neverbreak();
+ self.ibox(-INDENT);
+ self.ty(definition);
+ self.end();
+ self.where_clause_oneline_semi(&item.where_clause_after_eq);
+ } else {
+ self.where_clause_oneline_semi(&item.generics.where_clause);
+ }
+ self.end();
+ self.hardbreak();
+ }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 15a9e17..b8d5f04 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -179,8 +179,8 @@
//!
//! ```
//! // [dependencies]
-//! // prettyplease = "0.1"
-//! // syn = { version = "1", default-features = false, features = ["full", "parsing"] }
+//! // prettyplease = "0.2"
+//! // syn = { version = "2", default-features = false, features = ["full", "parsing"] }
//!
//! const INPUT: &str = stringify! {
//! use crate::{
@@ -320,7 +320,7 @@
//! these situations with conditional punctuation tokens whose selection can be
//! deferred and populated after it's known that the group is or is not broken.
-#![doc(html_root_url = "https://docs.rs/prettyplease/0.1.25")]
+#![doc(html_root_url = "https://docs.rs/prettyplease/0.2.6")]
#![allow(
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
diff --git a/src/lit.rs b/src/lit.rs
index c64b8a1..c38cf60 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -13,6 +13,8 @@ impl Printer {
Lit::Float(lit) => self.lit_float(lit),
Lit::Bool(lit) => self.lit_bool(lit),
Lit::Verbatim(lit) => self.lit_verbatim(lit),
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown Lit"),
}
}
diff --git a/src/mac.rs b/src/mac.rs
index 9c4c119..731b1f0 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -1,22 +1,19 @@
use crate::algorithm::Printer;
+use crate::path::PathKind;
use crate::token::Token;
use crate::INDENT;
use proc_macro2::{Delimiter, Spacing, TokenStream};
-use syn::{Ident, Macro, MacroDelimiter, PathArguments};
+use syn::{Ident, Macro, MacroDelimiter};
impl Printer {
- pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>) {
- let is_macro_rules = mac.path.leading_colon.is_none()
- && mac.path.segments.len() == 1
- && matches!(mac.path.segments[0].arguments, PathArguments::None)
- && mac.path.segments[0].ident == "macro_rules";
- if is_macro_rules {
+ pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>, semicolon: bool) {
+ if mac.path.is_ident("macro_rules") {
if let Some(ident) = ident {
self.macro_rules(ident, &mac.tokens);
return;
}
}
- self.path(&mac.path);
+ self.path(&mac.path, PathKind::Simple);
self.word("!");
if let Some(ident) = ident {
self.nbsp();
@@ -28,21 +25,22 @@ impl Printer {
MacroDelimiter::Bracket(_) => ("[", "]", Self::zerobreak as fn(&mut Self)),
};
self.word(open);
- self.cbox(INDENT);
- delimiter_break(self);
- self.ibox(0);
- self.macro_rules_tokens(mac.tokens.clone(), false);
- self.end();
- delimiter_break(self);
- self.offset(-INDENT);
- self.end();
+ if !mac.tokens.is_empty() {
+ self.cbox(INDENT);
+ delimiter_break(self);
+ self.ibox(0);
+ self.macro_rules_tokens(mac.tokens.clone(), false);
+ self.end();
+ delimiter_break(self);
+ self.offset(-INDENT);
+ self.end();
+ }
self.word(close);
- }
-
- pub fn mac_semi_if_needed(&mut self, delimiter: &MacroDelimiter) {
- match delimiter {
- MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => self.word(";"),
- MacroDelimiter::Brace(_) => {}
+ if semicolon {
+ match mac.delimiter {
+ MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => self.word(";"),
+ MacroDelimiter::Brace(_) => {}
+ }
}
}
@@ -126,7 +124,7 @@ impl Printer {
self.word("}");
}
- fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) {
+ pub fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) {
#[derive(PartialEq)]
enum State {
Start,
@@ -211,10 +209,10 @@ impl Printer {
fn is_keyword(ident: &Ident) -> bool {
match ident.to_string().as_str() {
- "as" | "box" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern"
- | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod"
- | "move" | "mut" | "pub" | "ref" | "return" | "static" | "struct" | "trait" | "type"
- | "unsafe" | "use" | "where" | "while" | "yield" => true,
+ "as" | "async" | "await" | "box" | "break" | "const" | "continue" | "crate" | "dyn"
+ | "else" | "enum" | "extern" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop"
+ | "macro" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "static"
+ | "struct" | "trait" | "type" | "unsafe" | "use" | "where" | "while" | "yield" => true,
_ => false,
}
}
diff --git a/src/pat.rs b/src/pat.rs
index 4cec22c..ba9c84d 100644
--- a/src/pat.rs
+++ b/src/pat.rs
@@ -1,22 +1,24 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
- FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference,
- PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, RangeLimits,
+ FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
+ PatTupleStruct, PatType, PatWild,
};
impl Printer {
pub fn pat(&mut self, pat: &Pat) {
match pat {
- Pat::Box(pat) => self.pat_box(pat),
+ Pat::Const(pat) => self.expr_const(pat),
Pat::Ident(pat) => self.pat_ident(pat),
- Pat::Lit(pat) => self.pat_lit(pat),
- Pat::Macro(pat) => self.pat_macro(pat),
+ Pat::Lit(pat) => self.expr_lit(pat),
+ Pat::Macro(pat) => self.expr_macro(pat),
Pat::Or(pat) => self.pat_or(pat),
- Pat::Path(pat) => self.pat_path(pat),
- Pat::Range(pat) => self.pat_range(pat),
+ Pat::Paren(pat) => self.pat_paren(pat),
+ Pat::Path(pat) => self.expr_path(pat),
+ Pat::Range(pat) => self.expr_range(pat),
Pat::Reference(pat) => self.pat_reference(pat),
Pat::Rest(pat) => self.pat_rest(pat),
Pat::Slice(pat) => self.pat_slice(pat),
@@ -31,12 +33,6 @@ impl Printer {
}
}
- fn pat_box(&mut self, pat: &PatBox) {
- self.outer_attrs(&pat.attrs);
- self.word("box ");
- self.pat(&pat.pat);
- }
-
fn pat_ident(&mut self, pat: &PatIdent) {
self.outer_attrs(&pat.attrs);
if pat.by_ref.is_some() {
@@ -52,16 +48,6 @@ impl Printer {
}
}
- fn pat_lit(&mut self, pat: &PatLit) {
- self.outer_attrs(&pat.attrs);
- self.expr(&pat.expr);
- }
-
- fn pat_macro(&mut self, pat: &PatMacro) {
- self.outer_attrs(&pat.attrs);
- self.mac(&pat.mac, None);
- }
-
fn pat_or(&mut self, pat: &PatOr) {
self.outer_attrs(&pat.attrs);
let mut consistent_break = false;
@@ -89,19 +75,11 @@ impl Printer {
self.end();
}
- fn pat_path(&mut self, pat: &PatPath) {
- self.outer_attrs(&pat.attrs);
- self.qpath(&pat.qself, &pat.path);
- }
-
- fn pat_range(&mut self, pat: &PatRange) {
+ fn pat_paren(&mut self, pat: &PatParen) {
self.outer_attrs(&pat.attrs);
- self.expr(&pat.lo);
- match &pat.limits {
- RangeLimits::HalfOpen(_) => self.word(".."),
- RangeLimits::Closed(_) => self.word("..="),
- }
- self.expr(&pat.hi);
+ self.word("(");
+ self.pat(&pat.pat);
+ self.word(")");
}
fn pat_reference(&mut self, pat: &PatReference) {
@@ -131,15 +109,15 @@ impl Printer {
fn pat_struct(&mut self, pat: &PatStruct) {
self.outer_attrs(&pat.attrs);
self.cbox(INDENT);
- self.path(&pat.path);
+ self.path(&pat.path, PathKind::Expr);
self.word(" {");
self.space_if_nonempty();
for field in pat.fields.iter().delimited() {
self.field_pat(&field);
- self.trailing_comma_or_space(field.is_last && pat.dot2_token.is_none());
+ self.trailing_comma_or_space(field.is_last && pat.rest.is_none());
}
- if pat.dot2_token.is_some() {
- self.word("..");
+ if let Some(rest) = &pat.rest {
+ self.pat_rest(rest);
self.space();
}
self.offset(-INDENT);
@@ -170,11 +148,11 @@ impl Printer {
fn pat_tuple_struct(&mut self, pat: &PatTupleStruct) {
self.outer_attrs(&pat.attrs);
- self.path(&pat.path);
+ self.path(&pat.path, PathKind::Expr);
self.word("(");
self.cbox(INDENT);
self.zerobreak();
- for elem in pat.pat.elems.iter().delimited() {
+ for elem in pat.elems.iter().delimited() {
self.pat(&elem);
self.trailing_comma(elem.is_last);
}
@@ -190,10 +168,68 @@ impl Printer {
self.ty(&pat.ty);
}
+ #[cfg(not(feature = "verbatim"))]
fn pat_verbatim(&mut self, pat: &TokenStream) {
unimplemented!("Pat::Verbatim `{}`", pat);
}
+ #[cfg(feature = "verbatim")]
+ fn pat_verbatim(&mut self, tokens: &TokenStream) {
+ use syn::parse::{Parse, ParseStream, Result};
+ use syn::{braced, Attribute, Block, Token};
+
+ enum PatVerbatim {
+ Box(Pat),
+ Const(PatConst),
+ }
+
+ struct PatConst {
+ attrs: Vec<Attribute>,
+ block: Block,
+ }
+
+ impl Parse for PatVerbatim {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![box]) {
+ input.parse::<Token![box]>()?;
+ let inner = Pat::parse_single(input)?;
+ Ok(PatVerbatim::Box(inner))
+ } 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(PatVerbatim::Const(PatConst {
+ attrs,
+ block: Block { brace_token, stmts },
+ }))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ let pat: PatVerbatim = match syn::parse2(tokens.clone()) {
+ Ok(pat) => pat,
+ Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens),
+ };
+
+ match pat {
+ PatVerbatim::Box(pat) => {
+ self.word("box ");
+ self.pat(&pat);
+ }
+ PatVerbatim::Const(pat) => {
+ self.word("const ");
+ self.cbox(INDENT);
+ self.small_block(&pat.block, &pat.attrs);
+ self.end();
+ }
+ }
+ }
+
fn pat_wild(&mut self, pat: &PatWild) {
self.outer_attrs(&pat.attrs);
self.word("_");
diff --git a/src/path.rs b/src/path.rs
index 53d4b4c..d704bfd 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -3,31 +3,41 @@ use crate::iter::IterDelimited;
use crate::INDENT;
use std::ptr;
use syn::{
- AngleBracketedGenericArguments, Binding, Constraint, Expr, GenericArgument,
+ AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, Expr, GenericArgument,
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
};
+#[derive(Copy, Clone, PartialEq)]
+pub enum PathKind {
+ // a::B
+ Simple,
+ // a::B<T>
+ Type,
+ // a::B::<T>
+ Expr,
+}
+
impl Printer {
- pub fn path(&mut self, path: &Path) {
+ pub fn path(&mut self, path: &Path, kind: PathKind) {
assert!(!path.segments.is_empty());
for segment in path.segments.iter().delimited() {
if !segment.is_first || path.leading_colon.is_some() {
self.word("::");
}
- self.path_segment(&segment);
+ self.path_segment(&segment, kind);
}
}
- pub fn path_segment(&mut self, segment: &PathSegment) {
+ pub fn path_segment(&mut self, segment: &PathSegment, kind: PathKind) {
self.ident(&segment.ident);
- self.path_arguments(&segment.arguments);
+ self.path_arguments(&segment.arguments, kind);
}
- fn path_arguments(&mut self, arguments: &PathArguments) {
+ fn path_arguments(&mut self, arguments: &PathArguments, kind: PathKind) {
match arguments {
PathArguments::None => {}
PathArguments::AngleBracketed(arguments) => {
- self.angle_bracketed_generic_arguments(arguments);
+ self.angle_bracketed_generic_arguments(arguments, kind);
}
PathArguments::Parenthesized(arguments) => {
self.parenthesized_generic_arguments(arguments);
@@ -39,8 +49,6 @@ impl Printer {
match arg {
GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime),
GenericArgument::Type(ty) => self.ty(ty),
- GenericArgument::Binding(binding) => self.binding(binding),
- GenericArgument::Constraint(constraint) => self.constraint(constraint),
GenericArgument::Const(expr) => {
match expr {
Expr::Lit(expr) => self.expr_lit(expr),
@@ -54,41 +62,51 @@ impl Printer {
}
}
}
+ GenericArgument::AssocType(assoc) => self.assoc_type(assoc),
+ GenericArgument::AssocConst(assoc) => self.assoc_const(assoc),
+ GenericArgument::Constraint(constraint) => self.constraint(constraint),
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown GenericArgument"),
}
}
- fn angle_bracketed_generic_arguments(&mut self, generic: &AngleBracketedGenericArguments) {
- if generic.args.is_empty() {
+ pub fn angle_bracketed_generic_arguments(
+ &mut self,
+ generic: &AngleBracketedGenericArguments,
+ path_kind: PathKind,
+ ) {
+ if generic.args.is_empty() || path_kind == PathKind::Simple {
return;
}
- if generic.colon2_token.is_some() {
+ if path_kind == PathKind::Expr {
self.word("::");
}
self.word("<");
self.cbox(INDENT);
self.zerobreak();
- // Print lifetimes before types and consts, all before bindings,
- // regardless of their order in self.args.
- //
- // TODO: ordering rules for const arguments vs type arguments have
- // not been settled yet. https://github.com/rust-lang/rust/issues/44580
+ // Print lifetimes before types/consts/bindings, regardless of their
+ // order in self.args.
#[derive(Ord, PartialOrd, Eq, PartialEq)]
enum Group {
First,
Second,
- Third,
}
fn group(arg: &GenericArgument) -> Group {
match arg {
GenericArgument::Lifetime(_) => Group::First,
- GenericArgument::Type(_) | GenericArgument::Const(_) => Group::Second,
- GenericArgument::Binding(_) | GenericArgument::Constraint(_) => Group::Third,
+ GenericArgument::Type(_)
+ | GenericArgument::Const(_)
+ | GenericArgument::AssocType(_)
+ | GenericArgument::AssocConst(_)
+ | GenericArgument::Constraint(_) => Group::Second,
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => Group::Second,
}
}
let last = generic.args.iter().max_by_key(|param| group(param));
- for current_group in [Group::First, Group::Second, Group::Third] {
+ for current_group in [Group::First, Group::Second] {
for arg in &generic.args {
if group(arg) == current_group {
self.generic_argument(arg);
@@ -102,14 +120,29 @@ impl Printer {
self.word(">");
}
- fn binding(&mut self, binding: &Binding) {
- self.ident(&binding.ident);
+ fn assoc_type(&mut self, assoc: &AssocType) {
+ self.ident(&assoc.ident);
+ if let Some(generics) = &assoc.generics {
+ self.angle_bracketed_generic_arguments(generics, PathKind::Type);
+ }
+ self.word(" = ");
+ self.ty(&assoc.ty);
+ }
+
+ fn assoc_const(&mut self, assoc: &AssocConst) {
+ self.ident(&assoc.ident);
+ if let Some(generics) = &assoc.generics {
+ self.angle_bracketed_generic_arguments(generics, PathKind::Type);
+ }
self.word(" = ");
- self.ty(&binding.ty);
+ self.expr(&assoc.value);
}
fn constraint(&mut self, constraint: &Constraint) {
self.ident(&constraint.ident);
+ if let Some(generics) = &constraint.generics {
+ self.angle_bracketed_generic_arguments(generics, PathKind::Type);
+ }
self.ibox(INDENT);
for bound in constraint.bounds.iter().delimited() {
if bound.is_first {
@@ -137,11 +170,11 @@ impl Printer {
self.end();
}
- pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path) {
+ pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind) {
let qself = match qself {
Some(qself) => qself,
None => {
- self.path(path);
+ self.path(path, kind);
return;
}
};
@@ -158,7 +191,7 @@ impl Printer {
if !segment.is_first || path.leading_colon.is_some() {
self.word("::");
}
- self.path_segment(&segment);
+ self.path_segment(&segment, PathKind::Type);
if segment.is_last {
self.word(">");
}
@@ -168,7 +201,7 @@ impl Printer {
}
for segment in segments {
self.word("::");
- self.path_segment(segment);
+ self.path_segment(segment, kind);
}
}
}
diff --git a/src/stmt.rs b/src/stmt.rs
index a127b57..268a79e 100644
--- a/src/stmt.rs
+++ b/src/stmt.rs
@@ -1,5 +1,6 @@
use crate::algorithm::Printer;
-use syn::{Expr, Stmt};
+use crate::INDENT;
+use syn::{BinOp, Expr, Stmt};
impl Printer {
pub fn stmt(&mut self, stmt: &Stmt) {
@@ -9,17 +10,32 @@ impl Printer {
self.ibox(0);
self.word("let ");
self.pat(&local.pat);
- if let Some((_eq, init)) = &local.init {
+ if let Some(local_init) = &local.init {
self.word(" = ");
self.neverbreak();
- self.expr(init);
+ self.expr(&local_init.expr);
+ if let Some((_else, diverge)) = &local_init.diverge {
+ self.word(" else ");
+ if let Expr::Block(expr) = diverge.as_ref() {
+ self.small_block(&expr.block, &[]);
+ } else {
+ self.word("{");
+ self.space();
+ self.ibox(INDENT);
+ self.expr(diverge);
+ self.end();
+ self.space();
+ self.offset(-INDENT);
+ self.word("}");
+ }
+ }
}
self.word(";");
self.end();
self.hardbreak();
}
Stmt::Item(item) => self.item(item),
- Stmt::Expr(expr) => {
+ Stmt::Expr(expr, None) => {
if break_after(expr) {
self.ibox(0);
self.expr_beginning_of_line(expr, true);
@@ -32,7 +48,7 @@ impl Printer {
self.expr_beginning_of_line(expr, true);
}
}
- Stmt::Semi(expr, _semi) => {
+ Stmt::Expr(expr, Some(_semi)) => {
if let Expr::Verbatim(tokens) = expr {
if tokens.is_empty() {
return;
@@ -46,19 +62,89 @@ impl Printer {
self.end();
self.hardbreak();
}
+ Stmt::Macro(stmt) => {
+ self.outer_attrs(&stmt.attrs);
+ let semicolon = true;
+ self.mac(&stmt.mac, None, semicolon);
+ self.hardbreak();
+ }
}
}
}
pub fn add_semi(expr: &Expr) -> bool {
match expr {
- Expr::Assign(_)
- | Expr::AssignOp(_)
- | Expr::Break(_)
- | Expr::Continue(_)
- | Expr::Return(_)
- | Expr::Yield(_) => true,
+ Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => {
+ true
+ }
+ Expr::Binary(expr) => match expr.op {
+ BinOp::AddAssign(_)
+ | BinOp::SubAssign(_)
+ | BinOp::MulAssign(_)
+ | BinOp::DivAssign(_)
+ | BinOp::RemAssign(_)
+ | BinOp::BitXorAssign(_)
+ | BinOp::BitAndAssign(_)
+ | BinOp::BitOrAssign(_)
+ | BinOp::ShlAssign(_)
+ | BinOp::ShrAssign(_) => true,
+ 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(_) => false,
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown BinOp"),
+ },
Expr::Group(group) => add_semi(&group.expr),
+
+ Expr::Array(_)
+ | Expr::Async(_)
+ | Expr::Await(_)
+ | Expr::Block(_)
+ | Expr::Call(_)
+ | Expr::Cast(_)
+ | Expr::Closure(_)
+ | Expr::Const(_)
+ | Expr::Field(_)
+ | Expr::ForLoop(_)
+ | Expr::If(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Loop(_)
+ | Expr::Macro(_)
+ | Expr::Match(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Struct(_)
+ | Expr::Try(_)
+ | Expr::TryBlock(_)
+ | Expr::Tuple(_)
+ | Expr::Unary(_)
+ | Expr::Unsafe(_)
+ | Expr::Verbatim(_)
+ | Expr::While(_) => false,
+
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => false,
}
}
@@ -80,6 +166,44 @@ fn remove_semi(expr: &Expr) -> bool {
Some((_else_token, else_branch)) => remove_semi(else_branch),
None => true,
},
+
+ Expr::Array(_)
+ | Expr::Assign(_)
+ | Expr::Async(_)
+ | Expr::Await(_)
+ | Expr::Binary(_)
+ | Expr::Block(_)
+ | Expr::Break(_)
+ | Expr::Call(_)
+ | Expr::Cast(_)
+ | Expr::Closure(_)
+ | Expr::Continue(_)
+ | Expr::Const(_)
+ | Expr::Field(_)
+ | Expr::Index(_)
+ | Expr::Infer(_)
+ | Expr::Let(_)
+ | Expr::Lit(_)
+ | Expr::Loop(_)
+ | Expr::Macro(_)
+ | Expr::Match(_)
+ | Expr::MethodCall(_)
+ | Expr::Paren(_)
+ | Expr::Path(_)
+ | Expr::Range(_)
+ | Expr::Reference(_)
+ | Expr::Repeat(_)
+ | Expr::Return(_)
+ | Expr::Struct(_)
+ | Expr::Try(_)
+ | Expr::TryBlock(_)
+ | Expr::Tuple(_)
+ | Expr::Unary(_)
+ | Expr::Unsafe(_)
+ | Expr::Verbatim(_)
+ | Expr::Yield(_) => false,
+
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => false,
}
}
diff --git a/src/ty.rs b/src/ty.rs
index 7bbdf46..0b72724 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -1,11 +1,12 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
+use crate::path::PathKind;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
- Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer,
- TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject,
- TypeTuple, Variadic,
+ Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
+ TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
+ TypeSlice, TypeTraitObject, TypeTuple,
};
impl Printer {
@@ -57,7 +58,7 @@ impl Printer {
self.trailing_comma(bare_fn_arg.is_last && ty.variadic.is_none());
}
if let Some(variadic) = &ty.variadic {
- self.variadic(variadic);
+ self.bare_variadic(variadic);
self.zerobreak();
}
self.offset(-INDENT);
@@ -86,7 +87,8 @@ impl Printer {
}
fn type_macro(&mut self, ty: &TypeMacro) {
- self.mac(&ty.mac, None);
+ let semicolon = false;
+ self.mac(&ty.mac, None, semicolon);
}
fn type_never(&mut self, ty: &TypeNever) {
@@ -101,7 +103,7 @@ impl Printer {
}
fn type_path(&mut self, ty: &TypePath) {
- self.qpath(&ty.qself, &ty.path);
+ self.qpath(&ty.qself, &ty.path, PathKind::Type);
}
fn type_ptr(&mut self, ty: &TypePtr) {
@@ -162,30 +164,56 @@ impl Printer {
#[cfg(not(feature = "verbatim"))]
fn type_verbatim(&mut self, ty: &TokenStream) {
- if ty.to_string() == "..." {
- self.word("...");
- } else {
- unimplemented!("Type::Verbatim `{}`", ty);
- }
+ unimplemented!("Type::Verbatim `{}`", ty);
}
#[cfg(feature = "verbatim")]
fn type_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
- use syn::{token, ExprBlock, Lit};
+ use syn::punctuated::Punctuated;
+ use syn::{Token, TypeParamBound};
enum TypeVerbatim {
- Lit(Lit),
- Block(ExprBlock),
+ DynStar(DynStar),
+ MutSelf(MutSelf),
+ NotType(NotType),
+ }
+
+ struct DynStar {
+ bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+
+ struct MutSelf {
+ ty: Option<Type>,
+ }
+
+ struct NotType {
+ inner: Type,
}
impl Parse for TypeVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
- if lookahead.peek(Lit) {
- input.parse().map(TypeVerbatim::Lit)
- } else if lookahead.peek(token::Brace) {
- input.parse().map(TypeVerbatim::Block)
+ if lookahead.peek(Token![dyn]) {
+ input.parse::<Token![dyn]>()?;
+ input.parse::<Token![*]>()?;
+ let bounds = input.parse_terminated(TypeParamBound::parse, Token![+])?;
+ Ok(TypeVerbatim::DynStar(DynStar { bounds }))
+ } else if lookahead.peek(Token![mut]) {
+ input.parse::<Token![mut]>()?;
+ input.parse::<Token![self]>()?;
+ let ty = if input.is_empty() {
+ None
+ } else {
+ input.parse::<Token![:]>()?;
+ let ty: Type = input.parse()?;
+ Some(ty)
+ };
+ Ok(TypeVerbatim::MutSelf(MutSelf { ty }))
+ } else if lookahead.peek(Token![!]) {
+ input.parse::<Token![!]>()?;
+ let inner: Type = input.parse()?;
+ Ok(TypeVerbatim::NotType(NotType { inner }))
} else {
Err(lookahead.error())
}
@@ -198,11 +226,25 @@ impl Printer {
};
match ty {
- TypeVerbatim::Lit(lit) => {
- self.lit(&lit);
+ TypeVerbatim::DynStar(ty) => {
+ self.word("dyn* ");
+ for type_param_bound in ty.bounds.iter().delimited() {
+ if !type_param_bound.is_first {
+ self.word(" + ");
+ }
+ self.type_param_bound(&type_param_bound);
+ }
+ }
+ TypeVerbatim::MutSelf(bare_fn_arg) => {
+ self.word("mut self");
+ if let Some(ty) = &bare_fn_arg.ty {
+ self.word(": ");
+ self.ty(ty);
+ }
}
- TypeVerbatim::Block(block) => {
- self.expr_block(&block);
+ TypeVerbatim::NotType(ty) => {
+ self.word("!");
+ self.ty(&ty.inner);
}
}
}
@@ -226,8 +268,12 @@ impl Printer {
self.ty(&bare_fn_arg.ty);
}
- fn variadic(&mut self, variadic: &Variadic) {
+ fn bare_variadic(&mut self, variadic: &BareVariadic) {
self.outer_attrs(&variadic.attrs);
+ if let Some((name, _colon)) = &variadic.name {
+ self.ident(name);
+ self.word(": ");
+ }
self.word("...");
}