Skip to content

Commit d4ec464

Browse files
authored
Rollup merge of #93102 - dtolnay:ringbuffer, r=lcnr
Pretty printer algorithm revamp step 3 This PR follows #93065 as a third chunk of minor modernizations backported from https://github.com/dtolnay/prettyplease into rustc_ast_pretty. I've broken this up into atomic commits that hopefully are sensible in isolation. At every commit, the pretty printer is compilable and has runtime behavior that is identical to before and after the PR. None of the refactoring so far changes behavior. This PR is the last chunk of non-behavior-changing cleanup. After this the **next PR** will begin backporting behavior changes from `prettyplease`, starting with block indentation: ```rust macro_rules! print_expr { ($expr:expr) => { println!("{}", stringify!($expr)); }; } fn main() { print_expr!(Struct { x: 0, y: 0 }); print_expr!(Structtttttttttttttttttttttttttttttttttttttttttttttttttt { xxxxxxxxx: 0, yyyyyyyyy: 0 }); } ``` Output currently on master (nowhere near modern Rust style): ```console Struct{x: 0, y: 0,} Structtttttttttttttttttttttttttttttttttttttttttttttttttt{xxxxxxxxx: 0, yyyyyyyyy: 0,} ``` After the upcoming PR for block indentation (based on dtolnay/prettyplease@401d60c): ```console Struct { x: 0, y: 0, } Structtttttttttttttttttttttttttttttttttttttttttttttttttt { xxxxxxxxx: 0, yyyyyyyyy: 0, } ``` And the PR after that, for intelligent trailing commas (based on dtolnay/prettyplease@e2a0297): ```console Struct { x: 0, y: 0 } Structtttttttttttttttttttttttttttttttttttttttttttttttttt { xxxxxxxxx: 0, yyyyyyyyy: 0, } ```
2 parents 51fd48f + 21c1571 commit d4ec464

File tree

2 files changed

+83
-133
lines changed

2 files changed

+83
-133
lines changed

compiler/rustc_ast_pretty/src/pp.rs

+77-128
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ mod ring;
137137
use ring::RingBuffer;
138138
use std::borrow::Cow;
139139
use std::collections::VecDeque;
140-
use std::fmt;
140+
use std::iter;
141141

142142
/// How to break. Described in more detail in the module docs.
143143
#[derive(Clone, Copy, PartialEq)]
@@ -175,27 +175,10 @@ impl Token {
175175
}
176176
}
177177

178-
impl fmt::Display for Token {
179-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180-
match *self {
181-
Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
182-
Token::Break(_) => f.write_str("BREAK"),
183-
Token::Begin(_) => f.write_str("BEGIN"),
184-
Token::End => f.write_str("END"),
185-
}
186-
}
187-
}
188-
189178
#[derive(Copy, Clone)]
190-
enum PrintStackBreak {
179+
enum PrintFrame {
191180
Fits,
192-
Broken(Breaks),
193-
}
194-
195-
#[derive(Copy, Clone)]
196-
struct PrintStackElem {
197-
offset: isize,
198-
pbreak: PrintStackBreak,
181+
Broken { offset: isize, breaks: Breaks },
199182
}
200183

201184
const SIZE_INFINITY: isize = 0xffff;
@@ -220,7 +203,7 @@ pub struct Printer {
220203
/// advancing.
221204
scan_stack: VecDeque<usize>,
222205
/// Stack of blocks-in-progress being flushed by print
223-
print_stack: Vec<PrintStackElem>,
206+
print_stack: Vec<PrintFrame>,
224207
/// Buffered indentation to avoid writing trailing whitespace
225208
pending_indentation: isize,
226209
/// The token most recently popped from the left boundary of the
@@ -260,8 +243,8 @@ impl Printer {
260243
}
261244

262245
/// Be very careful with this!
263-
pub fn replace_last_token_still_buffered(&mut self, t: Token) {
264-
self.buf.last_mut().unwrap().token = t;
246+
pub fn replace_last_token_still_buffered(&mut self, token: Token) {
247+
self.buf.last_mut().unwrap().token = token;
265248
}
266249

267250
fn scan_eof(&mut self) {
@@ -271,53 +254,53 @@ impl Printer {
271254
}
272255
}
273256

274-
fn scan_begin(&mut self, b: BeginToken) {
257+
fn scan_begin(&mut self, token: BeginToken) {
275258
if self.scan_stack.is_empty() {
276259
self.left_total = 1;
277260
self.right_total = 1;
278261
self.buf.clear();
279262
}
280-
let right = self.buf.push(BufEntry { token: Token::Begin(b), size: -self.right_total });
281-
self.scan_stack.push_front(right);
263+
let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });
264+
self.scan_stack.push_back(right);
282265
}
283266

284267
fn scan_end(&mut self) {
285268
if self.scan_stack.is_empty() {
286269
self.print_end();
287270
} else {
288271
let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
289-
self.scan_stack.push_front(right);
272+
self.scan_stack.push_back(right);
290273
}
291274
}
292275

293-
fn scan_break(&mut self, b: BreakToken) {
276+
fn scan_break(&mut self, token: BreakToken) {
294277
if self.scan_stack.is_empty() {
295278
self.left_total = 1;
296279
self.right_total = 1;
297280
self.buf.clear();
298281
} else {
299282
self.check_stack(0);
300283
}
301-
let right = self.buf.push(BufEntry { token: Token::Break(b), size: -self.right_total });
302-
self.scan_stack.push_front(right);
303-
self.right_total += b.blank_space;
284+
let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total });
285+
self.scan_stack.push_back(right);
286+
self.right_total += token.blank_space;
304287
}
305288

306-
fn scan_string(&mut self, s: Cow<'static, str>) {
289+
fn scan_string(&mut self, string: Cow<'static, str>) {
307290
if self.scan_stack.is_empty() {
308-
self.print_string(&s);
291+
self.print_string(&string);
309292
} else {
310-
let len = s.len() as isize;
311-
self.buf.push(BufEntry { token: Token::String(s), size: len });
293+
let len = string.len() as isize;
294+
self.buf.push(BufEntry { token: Token::String(string), size: len });
312295
self.right_total += len;
313296
self.check_stream();
314297
}
315298
}
316299

317300
fn check_stream(&mut self) {
318301
while self.right_total - self.left_total > self.space {
319-
if *self.scan_stack.back().unwrap() == self.buf.index_of_first() {
320-
self.scan_stack.pop_back().unwrap();
302+
if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
303+
self.scan_stack.pop_front().unwrap();
321304
self.buf.first_mut().unwrap().size = SIZE_INFINITY;
322305
}
323306
self.advance_left();
@@ -328,152 +311,118 @@ impl Printer {
328311
}
329312

330313
fn advance_left(&mut self) {
331-
let mut left_size = self.buf.first().unwrap().size;
332-
333-
while left_size >= 0 {
334-
let left = self.buf.first().unwrap().token.clone();
314+
while self.buf.first().unwrap().size >= 0 {
315+
let left = self.buf.pop_first().unwrap();
335316

336-
let len = match left {
337-
Token::Break(b) => b.blank_space,
338-
Token::String(ref s) => {
339-
let len = s.len() as isize;
340-
assert_eq!(len, left_size);
341-
len
317+
match &left.token {
318+
Token::String(string) => {
319+
self.left_total += string.len() as isize;
320+
self.print_string(string);
342321
}
343-
_ => 0,
344-
};
345-
346-
self.print(left, left_size);
322+
Token::Break(token) => {
323+
self.left_total += token.blank_space;
324+
self.print_break(*token, left.size);
325+
}
326+
Token::Begin(token) => self.print_begin(*token, left.size),
327+
Token::End => self.print_end(),
328+
}
347329

348-
self.left_total += len;
330+
self.last_printed = Some(left.token);
349331

350-
self.buf.advance_left();
351332
if self.buf.is_empty() {
352333
break;
353334
}
354-
355-
left_size = self.buf.first().unwrap().size;
356335
}
357336
}
358337

359-
fn check_stack(&mut self, mut k: usize) {
360-
while let Some(&x) = self.scan_stack.front() {
361-
let mut entry = &mut self.buf[x];
338+
fn check_stack(&mut self, mut depth: usize) {
339+
while let Some(&index) = self.scan_stack.back() {
340+
let mut entry = &mut self.buf[index];
362341
match entry.token {
363342
Token::Begin(_) => {
364-
if k == 0 {
343+
if depth == 0 {
365344
break;
366345
}
367-
self.scan_stack.pop_front().unwrap();
346+
self.scan_stack.pop_back().unwrap();
368347
entry.size += self.right_total;
369-
k -= 1;
348+
depth -= 1;
370349
}
371350
Token::End => {
372351
// paper says + not =, but that makes no sense.
373-
self.scan_stack.pop_front().unwrap();
352+
self.scan_stack.pop_back().unwrap();
374353
entry.size = 1;
375-
k += 1;
354+
depth += 1;
376355
}
377356
_ => {
378-
self.scan_stack.pop_front().unwrap();
357+
self.scan_stack.pop_back().unwrap();
379358
entry.size += self.right_total;
380-
if k == 0 {
359+
if depth == 0 {
381360
break;
382361
}
383362
}
384363
}
385364
}
386365
}
387366

388-
fn print_newline(&mut self, amount: isize) {
389-
self.out.push('\n');
390-
self.pending_indentation = 0;
391-
self.indent(amount);
392-
}
393-
394-
fn indent(&mut self, amount: isize) {
395-
self.pending_indentation += amount;
367+
fn get_top(&self) -> PrintFrame {
368+
*self
369+
.print_stack
370+
.last()
371+
.unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent })
396372
}
397373

398-
fn get_top(&self) -> PrintStackElem {
399-
*self.print_stack.last().unwrap_or({
400-
&PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
401-
})
402-
}
403-
404-
fn print_begin(&mut self, b: BeginToken, l: isize) {
405-
if l > self.space {
406-
let col = self.margin - self.space + b.offset;
407-
self.print_stack
408-
.push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
374+
fn print_begin(&mut self, token: BeginToken, size: isize) {
375+
if size > self.space {
376+
let col = self.margin - self.space + token.offset;
377+
self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks });
409378
} else {
410-
self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
379+
self.print_stack.push(PrintFrame::Fits);
411380
}
412381
}
413382

414383
fn print_end(&mut self) {
415384
self.print_stack.pop().unwrap();
416385
}
417386

418-
fn print_break(&mut self, b: BreakToken, l: isize) {
419-
let top = self.get_top();
420-
match top.pbreak {
421-
PrintStackBreak::Fits => {
422-
self.space -= b.blank_space;
423-
self.indent(b.blank_space);
424-
}
425-
PrintStackBreak::Broken(Breaks::Consistent) => {
426-
self.print_newline(top.offset + b.offset);
427-
self.space = self.margin - (top.offset + b.offset);
428-
}
429-
PrintStackBreak::Broken(Breaks::Inconsistent) => {
430-
if l > self.space {
431-
self.print_newline(top.offset + b.offset);
432-
self.space = self.margin - (top.offset + b.offset);
433-
} else {
434-
self.indent(b.blank_space);
435-
self.space -= b.blank_space;
387+
fn print_break(&mut self, token: BreakToken, size: isize) {
388+
let break_offset =
389+
match self.get_top() {
390+
PrintFrame::Fits => None,
391+
PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset),
392+
PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => {
393+
if size > self.space { Some(offset) } else { None }
436394
}
437-
}
395+
};
396+
if let Some(offset) = break_offset {
397+
self.out.push('\n');
398+
self.pending_indentation = offset + token.offset;
399+
self.space = self.margin - (offset + token.offset);
400+
} else {
401+
self.pending_indentation += token.blank_space;
402+
self.space -= token.blank_space;
438403
}
439404
}
440405

441-
fn print_string(&mut self, s: &str) {
442-
let len = s.len() as isize;
443-
// assert!(len <= space);
444-
self.space -= len;
445-
406+
fn print_string(&mut self, string: &str) {
446407
// Write the pending indent. A more concise way of doing this would be:
447408
//
448409
// write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
449410
//
450411
// But that is significantly slower. This code is sufficiently hot, and indents can get
451412
// sufficiently large, that the difference is significant on some workloads.
452413
self.out.reserve(self.pending_indentation as usize);
453-
self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
414+
self.out.extend(iter::repeat(' ').take(self.pending_indentation as usize));
454415
self.pending_indentation = 0;
455-
self.out.push_str(s);
456-
}
457416

458-
fn print(&mut self, token: Token, l: isize) {
459-
match &token {
460-
Token::Begin(b) => self.print_begin(*b, l),
461-
Token::End => self.print_end(),
462-
Token::Break(b) => self.print_break(*b, l),
463-
Token::String(s) => {
464-
let len = s.len() as isize;
465-
assert_eq!(len, l);
466-
self.print_string(s);
467-
}
468-
}
469-
self.last_printed = Some(token);
417+
self.out.push_str(string);
418+
self.space -= string.len() as isize;
470419
}
471420

472421
// Convenience functions to talk to the printer.
473422

474423
/// "raw box"
475-
pub fn rbox(&mut self, indent: usize, b: Breaks) {
476-
self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
424+
pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
425+
self.scan_begin(BeginToken { offset: indent as isize, breaks })
477426
}
478427

479428
/// Inconsistent breaking box
@@ -500,8 +449,8 @@ impl Printer {
500449
}
501450

502451
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
503-
let s = wrd.into();
504-
self.scan_string(s)
452+
let string = wrd.into();
453+
self.scan_string(string)
505454
}
506455

507456
fn spaces(&mut self, n: usize) {

compiler/rustc_ast_pretty/src/pp/ring.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ impl<T> RingBuffer<T> {
3232
index
3333
}
3434

35-
pub fn advance_left(&mut self) {
36-
self.data.pop_front().unwrap();
37-
self.offset += 1;
38-
}
39-
4035
pub fn clear(&mut self) {
4136
self.data.clear();
4237
}
@@ -53,6 +48,12 @@ impl<T> RingBuffer<T> {
5348
self.data.front_mut()
5449
}
5550

51+
pub fn pop_first(&mut self) -> Option<T> {
52+
let first = self.data.pop_front()?;
53+
self.offset += 1;
54+
Some(first)
55+
}
56+
5657
pub fn last(&self) -> Option<&T> {
5758
self.data.back()
5859
}

0 commit comments

Comments
 (0)