Files
ngr/src/syntax/pretty.rs

159 lines
5.9 KiB
Rust

use crate::syntax::ast::{ConstantType, Expression, Program, Statement, TopLevel, Value};
use crate::util::pretty::{derived_display, Allocator};
use pretty::{DocAllocator, DocBuilder};
impl Program {
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
let mut result = allocator.nil();
for tl in self.items.iter() {
result = result
.append(tl.pretty(allocator))
.append(allocator.text(";"))
.append(allocator.hardline());
}
result
}
}
impl TopLevel {
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
match self {
TopLevel::Statement(stmt) => stmt.pretty(allocator),
TopLevel::Function(name, arg_names, body) => allocator
.text("function")
.append(allocator.space())
.append(
name.as_ref()
.map(|x| allocator.text(x.to_string()))
.unwrap_or_else(|| allocator.nil()),
)
.append(
allocator
.intersperse(
arg_names.iter().map(|x| allocator.text(x.to_string())),
allocator.text(","),
)
.parens(),
)
.append(allocator.space())
.append(body.pretty(allocator)),
}
}
}
impl Statement {
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
match self {
Statement::Binding(_, var, expr) => allocator
.text(var.to_string())
.append(allocator.space())
.append(allocator.text("="))
.append(allocator.space())
.append(expr.pretty(allocator)),
Statement::Print(_, var) => allocator
.text("print")
.append(allocator.space())
.append(allocator.text(var.to_string())),
Statement::Expression(e) => e.pretty(allocator),
}
}
}
impl Expression {
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
match self {
Expression::Value(_, val) => val.pretty(allocator),
Expression::Reference(_, var) => allocator.text(var.to_string()),
Expression::Cast(_, t, e) => allocator
.text(t.clone())
.angles()
.append(e.pretty(allocator)),
Expression::Primitive(_, op, exprs) if exprs.len() == 1 => allocator
.text(op.to_string())
.append(exprs[0].pretty(allocator)),
Expression::Primitive(_, op, exprs) if exprs.len() == 2 => {
let left = exprs[0].pretty(allocator);
let right = exprs[1].pretty(allocator);
left.append(allocator.space())
.append(allocator.text(op.to_string()))
.append(allocator.space())
.append(right)
.parens()
}
Expression::Primitive(_, op, exprs) => {
let call = allocator.text(op.to_string());
let args = exprs.iter().map(|x| x.pretty(allocator));
let comma_sepped_args = allocator.intersperse(args, allocator.text(","));
call.append(comma_sepped_args.parens())
}
Expression::Call(_, fun, args) => {
let args = args.iter().map(|x| x.pretty(allocator));
let comma_sepped_args = allocator.intersperse(args, allocator.text(","));
fun.pretty(allocator).append(comma_sepped_args.parens())
}
Expression::Block(_, stmts) => match stmts.split_last() {
None => allocator.text("()"),
Some((last, &[])) => last.pretty(allocator),
Some((last, start)) => {
let mut result = allocator.text("{").append(allocator.hardline());
for stmt in start.iter() {
result = result
.append(stmt.pretty(allocator))
.append(allocator.text(";"))
.append(allocator.hardline());
}
result
.append(last.pretty(allocator))
.append(allocator.hardline())
.append(allocator.text("}"))
}
},
}
}
}
impl Value {
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
match self {
Value::Number(opt_base, ty, value) => {
let value_str = match opt_base {
None => format!("{}{}", value, type_suffix(ty)),
Some(2) => format!("0b{:b}{}", value, type_suffix(ty)),
Some(8) => format!("0o{:o}{}", value, type_suffix(ty)),
Some(10) => format!("0d{}{}", value, type_suffix(ty)),
Some(16) => format!("0x{:x}{}", value, type_suffix(ty)),
Some(_) => format!("!!{:x}{}!!", value, type_suffix(ty)),
};
allocator.text(value_str)
}
}
}
}
fn type_suffix(x: &Option<ConstantType>) -> &'static str {
match x {
None => "",
Some(ConstantType::Void) => "<void>",
Some(ConstantType::I8) => "i8",
Some(ConstantType::I16) => "i16",
Some(ConstantType::I32) => "i32",
Some(ConstantType::I64) => "i64",
Some(ConstantType::U8) => "u8",
Some(ConstantType::U16) => "u16",
Some(ConstantType::U32) => "u32",
Some(ConstantType::U64) => "u64",
}
}
derived_display!(Program);
derived_display!(TopLevel);
derived_display!(Statement);
derived_display!(Expression);
derived_display!(Value);