Skip to content

Commit

Permalink
feat(base): Add basic pretty printing of expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Jun 27, 2017
1 parent 793ac60 commit 68b3bb9
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 43 deletions.
10 changes: 10 additions & 0 deletions base/src/lib.rs
Expand Up @@ -42,6 +42,15 @@ macro_rules! type_cache {
}
}

macro_rules! chain {
($alloc: expr; $first: expr, $($rest: expr),+) => {{
let mut doc = ::pretty::DocBuilder($alloc, $first.into());
$(
doc = doc.append($rest);
)*
doc
}}
}

pub mod ast;
pub mod error;
Expand All @@ -50,6 +59,7 @@ pub mod fnv;
pub mod kind;
pub mod merge;
pub mod metadata;
pub mod pretty_print;
pub mod pos;
pub mod resolve;
pub mod scoped_map;
Expand Down
227 changes: 227 additions & 0 deletions base/src/pretty_print.rs
@@ -0,0 +1,227 @@
use pretty::{Arena, DocAllocator, DocBuilder};

use ast::{Expr, Literal, Pattern, SpannedExpr, SpannedPattern};
use types::{Type, pretty_print as pretty_type};

const INDENT: usize = 4;

pub fn pretty_pattern<'a, Id>(arena: &'a Arena<'a>,
pattern: &'a SpannedPattern<Id>)
-> DocBuilder<'a, Arena<'a>>
where Id: AsRef<str>,
{
match pattern.value {
Pattern::Constructor(ref ctor, ref args) => {
chain![arena;
ctor.as_ref(),
arena.concat(args.iter().map(|arg| {
arena.text(" ").append(pretty_pattern(arena, arg))
}))
]
}
Pattern::Ident(ref id) => arena.text(id.as_ref()),
Pattern::Record { ref fields, ref types, .. } => {
chain![arena;
"{",
arena.concat(types.iter().map(|field| {
chain![arena;
field.0.as_ref(),
",",
arena.newline()
]
})),
arena.concat(fields.iter().map(|field| {
match field.1 {
Some(ref new_name) => {
chain![arena;
field.0.as_ref(),
" = ",
pretty_pattern(arena, new_name),
",",
arena.newline()
]
}
None => {
chain![arena;
field.0.as_ref(),
",",
arena.newline()
]
}
}
})),
"}"
]
}
}
}

pub fn pretty_expr<'a, Id>(arena: &'a Arena<'a>, expr: &'a Expr<Id>) -> DocBuilder<'a, Arena<'a>>
where Id: AsRef<str>,
{
let pretty = |expr: &'a SpannedExpr<_>| pretty_expr(arena, &expr.value);
match *expr {
Expr::App(ref func, ref args) => {
pretty(func)
.append(arena.concat(args.iter().map(|arg| arena.text(" ").append(pretty(arg)))))
}
Expr::Array(ref array) => {
arena.text("[")
.append(arena.concat(array.exprs.iter().map(|elem| pretty(elem).append(", "))))
.append("]")
.group()
}
Expr::Block(ref elems) => {
arena.concat(elems.iter().map(|elem| pretty(elem).append(arena.newline())))
}
Expr::Ident(ref id) => arena.text(id.name.as_ref()),
Expr::IfElse(ref body, ref if_true, ref if_false) => {
chain![arena;
"if",
pretty(body),
"then",
pretty(if_true),
"else",
pretty(if_false)
]
}
Expr::Infix(ref l, ref op, ref r) => {
chain![arena;
pretty(l),
" ",
op.value.name.as_ref(),
" ",
pretty(r)
]
}
Expr::Lambda(ref lambda) => {
chain![arena;
"\\",
arena.concat(lambda.args.iter().map(|arg| arena.text(arg.name.as_ref()).append(" "))),
"->",
pretty(&lambda.body)
]
}
Expr::LetBindings(ref binds, ref body) => {
chain![arena;
"let ",
arena.concat(binds.iter().map(|bind| {
chain![arena;
chain![arena;
pretty_pattern(arena, &bind.name),
" ",
arena.concat(bind.args.iter().map(|arg| {
arena.text(arg.name.as_ref()).append(" ")
}))
].group(),
match *bind.typ {
Type::Hole => arena.nil(),
ref typ => arena.text(": ").append(pretty_type(arena, typ)),
},
"=",
arena.newline()
.append(pretty(&bind.expr))
.group(),
arena.newline()
].group().nest(INDENT)
})),
"in",
arena.newline(),
pretty(body)
]
}
Expr::Literal(ref literal) => {
match *literal {
Literal::Byte(b) => arena.text(format!("b{}", b)),
Literal::Char(c) => arena.text(format!("{:?}", c)),
Literal::Float(f) => arena.text(format!("{}", f)),
Literal::Int(i) => arena.text(format!("{}", i)),
Literal::String(ref s) => arena.text(format!("{:?}", s)),
}
}
Expr::Match(ref expr, ref alts) => {
chain![arena;
"match ",
pretty(expr),
" with",
arena.newline(),
arena.concat(alts.iter().map(|alt| {
chain![arena;
"| ",
pretty_pattern(arena, &alt.pattern),
" ->",
arena.newline(),
pretty(&alt.expr).group().nest(INDENT),
arena.newline()
]
}))
]
}
Expr::Projection(ref expr, ref field, _) => {
chain![arena;
pretty(expr),
".",
field.as_ref()
]
}
Expr::Record { ref types, ref exprs, .. } => {
chain![arena;
"{",
arena.concat(types.iter().map(|field| {
chain![arena;
field.name.as_ref(),
",",
arena.newline()
]
})),
arena.concat(exprs.iter().map(|field| {
chain![arena;
field.name.as_ref(),
match field.value {
Some(ref expr) => {
chain![arena;
" =",
arena.newline(),
pretty(&expr)
]
},
None => arena.nil(),
},
",",
arena.newline()
]
})),
"}"
]
}
Expr::Tuple(ref exprs) => {
arena.text("(")
.append(arena.concat(exprs.iter().map(|elem| pretty(elem).append(", "))))
.append(")")
.group()
}
Expr::TypeBindings(ref binds, ref body) => {
chain![arena;
"type ",
arena.concat(binds.iter().map(|bind| {
chain![arena;
bind.name.as_ref(),
" ",
arena.concat(bind.alias.args.iter().map(|arg| {
arena.text(arg.id.as_ref()).append(" ")
})),
"=",
arena.newline()
.append(pretty_type(arena, &bind.alias.unresolved_type()))
.group()
].group().nest(INDENT)
})),
arena.newline(),
"in",
arena.newline(),
pretty(body)
]
}
Expr::Error => arena.text("<error expr>"),
}
}

0 comments on commit 68b3bb9

Please sign in to comment.