Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty printer algorithm revamp step 2 #93065

Merged
merged 15 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 61 additions & 97 deletions compiler/rustc_ast_pretty/src/pp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,9 @@ pub enum Token {
Break(BreakToken),
Begin(BeginToken),
End,
Eof,
}

impl Token {
crate fn is_eof(&self) -> bool {
matches!(self, Token::Eof)
}

pub fn is_hardbreak_tok(&self) -> bool {
matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
}
Expand All @@ -187,7 +182,6 @@ impl fmt::Display for Token {
Token::Break(_) => f.write_str("BREAK"),
Token::Begin(_) => f.write_str("BEGIN"),
Token::End => f.write_str("END"),
Token::Eof => f.write_str("EOF"),
}
}
}
Expand All @@ -212,10 +206,6 @@ pub struct Printer {
margin: isize,
/// Number of spaces left on line
space: isize,
/// Index of left side of input stream
left: usize,
/// Index of right side of input stream
right: usize,
/// Ring-buffer of tokens and calculated sizes
buf: RingBuffer<BufEntry>,
/// Running size of stream "...left"
Expand All @@ -233,6 +223,9 @@ pub struct Printer {
print_stack: Vec<PrintStackElem>,
/// Buffered indentation to avoid writing trailing whitespace
pending_indentation: isize,
/// The token most recently popped from the left boundary of the
/// ring-buffer for printing
last_printed: Option<Token>,
}

#[derive(Clone)]
Expand All @@ -241,39 +234,34 @@ struct BufEntry {
size: isize,
}

impl Default for BufEntry {
fn default() -> Self {
BufEntry { token: Token::Eof, size: 0 }
}
}

impl Printer {
pub fn new() -> Self {
let linewidth = 78;
let mut buf = RingBuffer::new();
buf.advance_right();
Printer {
out: String::new(),
margin: linewidth as isize,
space: linewidth as isize,
left: 0,
right: 0,
buf,
buf: RingBuffer::new(),
left_total: 0,
right_total: 0,
scan_stack: VecDeque::new(),
print_stack: Vec::new(),
pending_indentation: 0,
last_printed: None,
}
}

pub fn last_token(&self) -> Token {
self.buf[self.right].token.clone()
pub fn last_token(&self) -> Option<&Token> {
self.last_token_still_buffered().or_else(|| self.last_printed.as_ref())
}

pub fn last_token_still_buffered(&self) -> Option<&Token> {
self.buf.last().map(|last| &last.token)
}

/// Be very careful with this!
pub fn replace_last_token(&mut self, t: Token) {
self.buf[self.right].token = t;
pub fn replace_last_token_still_buffered(&mut self, t: Token) {
self.buf.last_mut().unwrap().token = t;
}

fn scan_eof(&mut self) {
Expand All @@ -287,89 +275,63 @@ impl Printer {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
self.right = self.left;
self.buf.truncate(1);
} else {
self.advance_right();
self.buf.clear();
}
self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
let right = self.buf.push(BufEntry { token: Token::Begin(b), size: -self.right_total });
self.scan_stack.push_front(right);
}

fn scan_end(&mut self) {
if self.scan_stack.is_empty() {
self.print_end();
} else {
self.advance_right();
self.scan_push(BufEntry { token: Token::End, size: -1 });
let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
self.scan_stack.push_front(right);
}
}

fn scan_break(&mut self, b: BreakToken) {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
self.right = self.left;
self.buf.truncate(1);
self.buf.clear();
} else {
self.advance_right();
self.check_stack(0);
}
self.check_stack(0);
self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
let right = self.buf.push(BufEntry { token: Token::Break(b), size: -self.right_total });
self.scan_stack.push_front(right);
self.right_total += b.blank_space;
}

fn scan_string(&mut self, s: Cow<'static, str>) {
if self.scan_stack.is_empty() {
self.print_string(s);
self.print_string(&s);
} else {
self.advance_right();
let len = s.len() as isize;
self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
self.buf.push(BufEntry { token: Token::String(s), size: len });
self.right_total += len;
self.check_stream();
}
}

fn check_stream(&mut self) {
if self.right_total - self.left_total > self.space {
if Some(&self.left) == self.scan_stack.back() {
let scanned = self.scan_pop_bottom();
self.buf[scanned].size = SIZE_INFINITY;
while self.right_total - self.left_total > self.space {
if *self.scan_stack.back().unwrap() == self.buf.index_of_first() {
self.scan_stack.pop_back().unwrap();
self.buf.first_mut().unwrap().size = SIZE_INFINITY;
}
self.advance_left();
if self.left != self.right {
self.check_stream();
if self.buf.is_empty() {
break;
}
}
}

fn scan_push(&mut self, entry: BufEntry) {
self.buf[self.right] = entry;
self.scan_stack.push_front(self.right);
}

fn scan_pop(&mut self) -> usize {
self.scan_stack.pop_front().unwrap()
}

fn scan_top(&self) -> usize {
*self.scan_stack.front().unwrap()
}

fn scan_pop_bottom(&mut self) -> usize {
self.scan_stack.pop_back().unwrap()
}

fn advance_right(&mut self) {
self.right += 1;
self.buf.advance_right();
}

fn advance_left(&mut self) {
let mut left_size = self.buf[self.left].size;
let mut left_size = self.buf.first().unwrap().size;

while left_size >= 0 {
let left = self.buf[self.left].token.clone();
let left = self.buf.first().unwrap().token.clone();

let len = match left {
Token::Break(b) => b.blank_space,
Expand All @@ -385,39 +347,38 @@ impl Printer {

self.left_total += len;

if self.left == self.right {
self.buf.advance_left();
if self.buf.is_empty() {
break;
}

self.buf.advance_left();
self.left += 1;

left_size = self.buf[self.left].size;
left_size = self.buf.first().unwrap().size;
}
}

fn check_stack(&mut self, k: usize) {
if !self.scan_stack.is_empty() {
let x = self.scan_top();
match self.buf[x].token {
fn check_stack(&mut self, mut k: usize) {
while let Some(&x) = self.scan_stack.front() {
let mut entry = &mut self.buf[x];
match entry.token {
Token::Begin(_) => {
if k > 0 {
self.scan_pop();
self.buf[x].size += self.right_total;
self.check_stack(k - 1);
if k == 0 {
break;
}
self.scan_stack.pop_front().unwrap();
entry.size += self.right_total;
k -= 1;
}
Token::End => {
// paper says + not =, but that makes no sense.
self.scan_pop();
self.buf[x].size = 1;
self.check_stack(k + 1);
self.scan_stack.pop_front().unwrap();
entry.size = 1;
k += 1;
}
_ => {
self.scan_pop();
self.buf[x].size += self.right_total;
if k > 0 {
self.check_stack(k);
self.scan_stack.pop_front().unwrap();
entry.size += self.right_total;
if k == 0 {
break;
}
}
}
Expand Down Expand Up @@ -477,7 +438,7 @@ impl Printer {
}
}

fn print_string(&mut self, s: Cow<'static, str>) {
fn print_string(&mut self, s: &str) {
let len = s.len() as isize;
// assert!(len <= space);
self.space -= len;
Expand All @@ -491,21 +452,21 @@ impl Printer {
self.out.reserve(self.pending_indentation as usize);
self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
self.pending_indentation = 0;
self.out.push_str(&s);
self.out.push_str(s);
}

fn print(&mut self, token: Token, l: isize) {
match token {
Token::Begin(b) => self.print_begin(b, l),
match &token {
Token::Begin(b) => self.print_begin(*b, l),
Token::End => self.print_end(),
Token::Break(b) => self.print_break(b, l),
Token::Break(b) => self.print_break(*b, l),
Token::String(s) => {
let len = s.len() as isize;
assert_eq!(len, l);
self.print_string(s);
}
Token::Eof => panic!(), // Eof should never get here.
}
self.last_printed = Some(token);
}

// Convenience functions to talk to the printer.
Expand Down Expand Up @@ -560,7 +521,10 @@ impl Printer {
}

pub fn is_beginning_of_line(&self) -> bool {
self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
match self.last_token() {
Some(last_token) => last_token.is_hardbreak_tok(),
None => true,
}
}

pub fn hardbreak_tok_offset(off: isize) -> Token {
Expand Down
37 changes: 30 additions & 7 deletions compiler/rustc_ast_pretty/src/pp/ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,43 @@ impl<T> RingBuffer<T> {
RingBuffer { data: VecDeque::new(), offset: 0 }
}

pub fn advance_right(&mut self)
where
T: Default,
{
self.data.push_back(T::default());
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}

pub fn push(&mut self, value: T) -> usize {
let index = self.offset + self.data.len();
self.data.push_back(value);
index
}

pub fn advance_left(&mut self) {
self.data.pop_front().unwrap();
self.offset += 1;
}

pub fn truncate(&mut self, len: usize) {
self.data.truncate(len);
pub fn clear(&mut self) {
self.data.clear();
}

pub fn index_of_first(&self) -> usize {
self.offset
}

pub fn first(&self) -> Option<&T> {
self.data.front()
}

pub fn first_mut(&mut self) -> Option<&mut T> {
self.data.front_mut()
}

pub fn last(&self) -> Option<&T> {
self.data.back()
}

pub fn last_mut(&mut self) -> Option<&mut T> {
self.data.back_mut()
}
}

Expand Down
20 changes: 12 additions & 8 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,9 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
CommentStyle::BlankLine => {
// We need to do at least one, possibly two hardbreaks.
let twice = match self.last_token() {
pp::Token::String(s) => ";" == s,
pp::Token::Begin(_) => true,
pp::Token::End => true,
Some(pp::Token::String(s)) => ";" == s,
Some(pp::Token::Begin(_)) => true,
Some(pp::Token::End) => true,
_ => false,
};
if twice {
Expand Down Expand Up @@ -687,11 +687,15 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
if !self.is_beginning_of_line() {
self.break_offset(n, off)
} else if off != 0 && self.last_token().is_hardbreak_tok() {
// We do something pretty sketchy here: tuck the nonzero
// offset-adjustment we were going to deposit along with the
// break into the previous hardbreak.
self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
} else if off != 0 {
if let Some(last_token) = self.last_token_still_buffered() {
if last_token.is_hardbreak_tok() {
// We do something pretty sketchy here: tuck the nonzero
// offset-adjustment we were going to deposit along with the
// break into the previous hardbreak.
self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
}
}
}
}

Expand Down