Make code generic over allocator

This way, I can use the same code with any allocator I want. More
importantly, I can also use the nice DocBuilder-exclusive helper
functions!
This commit is contained in:
Joscha 2022-11-20 21:41:05 +01:00
parent 1a3772e6f7
commit 2ba56f0c92
4 changed files with 45 additions and 43 deletions

View file

@ -1,6 +1,7 @@
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use ::pretty::{Pretty, RcAllocator};
use chumsky::Parser as _; use chumsky::Parser as _;
use clap::Parser; use clap::Parser;
@ -48,7 +49,7 @@ fn main() -> anyhow::Result<()> {
match parser::parser().parse(stream) { match parser::parser().parse(stream) {
Ok(program) => { Ok(program) => {
let mut out = vec![]; let mut out = vec![];
program.to_doc().render(100, &mut out)?; program.pretty(&RcAllocator).render(100, &mut out)?;
println!("{}", String::from_utf8(out)?); println!("{}", String::from_utf8(out)?);
} }
Err(errs) => { Err(errs) => {

View file

@ -1,37 +1,36 @@
use pretty::RcDoc; use pretty::{DocAllocator, DocBuilder};
use crate::ast::Separated; use crate::ast::Separated;
impl<E, S1, S2> Separated<E, S1, S2> { impl<E, S1, S2> Separated<E, S1, S2> {
pub fn to_doc<FE, FS1, FS2>( pub fn pretty<'a, D, FE, FS1, FS2>(
&self, self,
allocator: &'a D,
elem_to_doc: FE, elem_to_doc: FE,
separator_to_doc: FS1, separator_to_doc: FS1,
trailing_separator_to_doc: FS2, trailing_separator_to_doc: FS2,
) -> RcDoc ) -> DocBuilder<'a, D>
where where
FE: Fn(&E) -> RcDoc, D: DocAllocator<'a>,
FS1: Fn(&S1) -> RcDoc, FE: Fn(&'a D, E) -> DocBuilder<'a, D>,
FS2: Fn(&S2) -> RcDoc, FS1: Fn(&'a D, S1) -> DocBuilder<'a, D>,
FS2: Fn(&'a D, S2) -> DocBuilder<'a, D>,
{ {
match self { match self {
Separated::Empty(_) => RcDoc::nil(), Separated::Empty(_) => allocator.nil(),
Separated::NonEmpty { Separated::NonEmpty {
first_elem, first_elem,
last_elems, last_elems,
trailing, trailing,
span: _span, span: _span,
} => elem_to_doc(first_elem) } => elem_to_doc(allocator, first_elem)
.append(RcDoc::concat( .append(allocator.concat(last_elems.into_iter().map(|(s, e)| {
last_elems separator_to_doc(allocator, s).append(elem_to_doc(allocator, e))
.iter() })))
.map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))),
))
.append( .append(
trailing trailing
.as_ref() .map(|s| trailing_separator_to_doc(allocator, s))
.map(trailing_separator_to_doc) .unwrap_or_else(|| allocator.nil()),
.unwrap_or_else(RcDoc::nil),
), ),
} }
} }

View file

@ -1,23 +1,23 @@
use pretty::RcDoc; use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Expr; use crate::ast::Expr;
impl Expr { impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr {
pub fn to_doc(&self) -> RcDoc { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Expr::Lit(lit) => RcDoc::text("<lit>"), Expr::Lit(lit) => allocator.text("<lit>"),
Expr::Call(call) => RcDoc::text("<call>"), Expr::Call(call) => allocator.text("<call>"),
Expr::Field(field) => RcDoc::text("<field>"), Expr::Field(field) => allocator.text("<field>"),
Expr::Var(var) => RcDoc::text("<var>"), Expr::Var(var) => allocator.text("<var>"),
Expr::TableConstr(constr) => RcDoc::text("<onstr>"), Expr::TableConstr(constr) => allocator.text("<onstr>"),
Expr::TableDestr(destr) => RcDoc::text("<destr>"), Expr::TableDestr(destr) => allocator.text("<destr>"),
Expr::FuncDef(def) => RcDoc::text("<def>"), Expr::FuncDef(def) => allocator.text("<def>"),
Expr::Paren { Expr::Paren {
s0, s0,
inner, inner,
s1, s1,
span: _, span: _,
} => RcDoc::text("(").append(inner.to_doc()).append(")"), } => inner.pretty(allocator).parens(),
// TODO Check whether parentheses are necessary // TODO Check whether parentheses are necessary
Expr::Neg { Expr::Neg {
@ -25,7 +25,7 @@ impl Expr {
s0, s0,
expr, expr,
span: _, span: _,
} => RcDoc::text("-").append(expr.to_doc()), } => allocator.text("-").append(expr.pretty(allocator)),
// TODO Check whether parentheses are necessary // TODO Check whether parentheses are necessary
Expr::Not { Expr::Not {
@ -33,7 +33,7 @@ impl Expr {
s0, s0,
expr, expr,
span: _, span: _,
} => RcDoc::text("not ").append(expr.to_doc()), } => allocator.text("not ").append(expr.pretty(allocator)),
Expr::BinOp { Expr::BinOp {
left, left,
@ -42,7 +42,7 @@ impl Expr {
s1, s1,
right, right,
span: _, span: _,
} => RcDoc::text("<binop>"), } => allocator.text("<binop>"),
} }
} }
} }

View file

@ -1,29 +1,31 @@
use pretty::RcDoc; use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Program; use crate::ast::Program;
impl Program { impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program {
pub fn to_doc(&self) -> RcDoc { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Program::Expr { Program::Expr {
s0, s0,
expr, expr,
s1, s1,
span: _, span: _,
} => expr.to_doc(), } => expr.pretty(allocator),
Program::Module { Program::Module {
s0, s0,
s1, s1,
elems, elems,
s2, s2,
span: _, span: _,
} => RcDoc::text("module") } => allocator
.append(RcDoc::line()) .text("module")
.append(RcDoc::line()) .append(allocator.line())
.append(elems.to_doc( .append(allocator.line())
|e| RcDoc::text("<elem>"), .append(elems.pretty(
|(s0, s1)| RcDoc::text(",").append(RcDoc::line()), allocator,
|s| RcDoc::text(","), |a, e| a.text("<elem>"),
|a, (s0, s1)| a.text(",").append(a.line()),
|a, s| a.text(","),
)), )),
} }
} }