#![allow(unused_variables)]
mod common;
mod defs;
mod expr;
mod test;
mod types;
use crate::codespan;
use crate::parser::{Token, TokenKind};
use crate::pr;
pub use defs::print_def_signature;
pub fn print_ty(ty: &pr::Ty) -> String {
let mut p = Printer::new(&CONFIG_NO_WRAP, None);
ty.print(&mut p).unwrap();
assert!(p.edits.is_empty());
p.buffer
}
pub fn print_source(
source: &pr::Source,
trivia: Option<&[Token]>,
) -> Vec<codespan::TextEdit<'static>> {
let mut p = Printer::new(&CONFIG_PRETTY, trivia);
p.buffer_span.source_id = source.span.source_id;
source.print(&mut p).unwrap();
p.finish_edit();
p.edits
}
trait PrintSource {
#[must_use]
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()>;
fn span(&self) -> Option<crate::Span>;
}
struct Printer<'c> {
config: &'c Config,
buffer: String,
buffer_span: crate::Span,
rem_width: u16,
indent: u16,
single_line: bool,
pending_suffix: u16,
trivia: Option<&'c [Token]>,
edits: Vec<codespan::TextEdit<'static>>,
}
struct Config {
indent_size: u16,
max_width: u16,
}
const CONFIG_PRETTY: Config = Config {
indent_size: 2,
max_width: 80,
};
const CONFIG_NO_WRAP: Config = Config {
indent_size: 2,
max_width: u16::MAX,
};
impl<'c> Printer<'c> {
fn new(config: &'c Config, trivia: Option<&'c [Token]>) -> Printer<'c> {
Printer {
config,
buffer: String::new(),
buffer_span: crate::Span {
source_id: 0, start: 0,
len: 0,
},
indent: 0,
rem_width: config.max_width,
single_line: false,
pending_suffix: 0,
trivia,
edits: Vec::new(),
}
}
#[must_use]
fn push<S: AsRef<str>>(&mut self, snippet: S) -> Option<()> {
for c in snippet.as_ref().chars() {
if c == '\n' {
self.rem_width = self.config.max_width;
continue;
}
if self.rem_width == 0 {
return None;
}
self.rem_width -= 1;
}
self.buffer += snippet.as_ref();
Some(())
}
fn push_unchecked<S: AsRef<str>>(&mut self, snippet: S) {
self.buffer += snippet.as_ref();
}
fn mark_printed(&mut self, span: &Option<crate::Span>) {
if let Some(span) = span {
self.buffer_span.set_end_of(span);
}
}
fn mark_printed_up_to(&mut self, offset: u32) {
self.buffer_span.set_end(offset);
}
fn fork(&self) -> Printer<'c> {
Printer {
config: self.config,
buffer: String::new(),
buffer_span: crate::Span {
source_id: self.buffer_span.source_id,
start: self.buffer_span.end(),
len: 0,
},
rem_width: self.rem_width,
indent: self.indent,
single_line: self.single_line,
pending_suffix: self.pending_suffix,
trivia: self.trivia,
edits: Vec::new(),
}
}
fn merge(&mut self, forked: Printer<'c>) {
self.rem_width = forked.rem_width;
self.trivia = forked.trivia;
if forked.edits.is_empty() {
self.buffer += &forked.buffer;
self.buffer_span.set_end_of(&forked.buffer_span);
return;
}
self.finish_edit();
self.edits.extend(forked.edits);
self.buffer = forked.buffer;
self.buffer_span = forked.buffer_span;
}
#[must_use]
fn consume(&mut self, width: usize) -> Option<()> {
self.rem_width = self.rem_width.checked_sub(width as u16)?;
Some(())
}
fn indent(&mut self) {
self.indent += 1;
}
fn dedent(&mut self) {
self.indent -= 1;
}
fn new_line(&mut self) {
let indent_width = self.indent * self.config.indent_size;
self.rem_width = self.config.max_width.saturating_sub(indent_width);
self.pending_suffix = 0;
let len_without_trailing_whitespace = self.buffer.trim_end_matches(' ').len();
self.buffer.truncate(len_without_trailing_whitespace);
self.buffer.push('\n');
self.buffer.push_str(&" ".repeat(indent_width as usize));
}
#[must_use]
fn require_single_line(&mut self, span: Option<crate::Span>) -> Option<()> {
self.single_line = true;
self.consume(self.pending_suffix as usize)?;
self.pending_suffix = 0;
self.validate_no_comments(span.map(|s| s.end()))?;
Some(())
}
fn take_trivia(&mut self, until: u32) -> Option<&'c Token> {
let trivia = self.trivia.as_mut()?;
let t = trivia.first().filter(|t| t.span.end() <= until)?;
*trivia = &trivia[1..];
Some(t)
}
fn take_trivia_comment(&mut self, until: u32) -> Option<&'c str> {
let trivia = self.trivia.as_mut()?;
let t = trivia.first().filter(|t| t.span.end() <= until)?;
let TokenKind::Comment(s) = &t.kind else {
return None;
};
*trivia = &trivia[1..];
Some(s)
}
fn take_trivia_new_line(&mut self, until: u32) -> Option<()> {
let trivia = self.trivia.as_mut()?;
let t = trivia.first().filter(|t| t.span.end() <= until)?;
let TokenKind::NewLine = &t.kind else {
return None;
};
*trivia = &trivia[1..];
Some(())
}
fn inject_trivia_leading(&mut self, until: Option<u32>) {
let Some(until) = until else { return };
let mut nl_count = 0;
while let Some(trivia) = self.take_trivia(until) {
match &trivia.kind {
TokenKind::NewLine => {
nl_count += 1;
if nl_count == 2 {
self.new_line();
}
}
TokenKind::Comment(comment) => {
self.push_unchecked("# ");
self.push_unchecked(comment);
self.new_line();
nl_count = 0;
}
_ => (),
}
}
}
fn inject_trivia_prev_inline(&mut self, until: Option<u32>) {
let Some(until) = until else { return };
while let Some(comment) = self.take_trivia_comment(until) {
self.push_unchecked(" # ");
self.push_unchecked(comment);
}
}
fn inject_trivia_trailing(&mut self, until: Option<u32>) {
let Some(until) = until else { return };
let mut had_empty_line = false;
while let Some(token) = self.take_trivia(until) {
let TokenKind::Comment(comment) = &token.kind else {
continue;
};
self.new_line();
if !had_empty_line {
self.new_line();
had_empty_line = true;
}
self.push_unchecked("# ");
self.push_unchecked(comment);
}
}
fn validate_no_comments(&mut self, until: Option<u32>) -> Option<()> {
let Some(until) = until else {
return Some(());
};
while let Some(trivia) = self.take_trivia(until) {
if let TokenKind::Comment(comment) = &trivia.kind {
return None;
}
}
Some(())
}
fn finish_edit(&mut self) {
if self.buffer.is_empty() && self.buffer_span.len == 0 {
return;
}
let code = std::mem::take(&mut self.buffer);
self.edits
.push(codespan::TextEdit::new(self.buffer_span, code));
self.buffer_span.start = self.buffer_span.end();
self.buffer_span.len = 0;
}
}
impl std::fmt::Debug for Printer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Printer")
.field("rem_width", &self.rem_width)
.field("single_line", &self.single_line)
.field("pending_suffix", &self.pending_suffix)
.finish()
}
}
impl<T> PrintSource for &T
where
T: PrintSource,
{
fn print<'c>(&self, p: &mut Printer<'c>) -> Option<()> {
T::print(self, p)
}
fn span(&self) -> Option<crate::Span> {
T::span(self)
}
}