Move pretty-printing to its own module.
This commit is contained in:
@@ -2,6 +2,7 @@ use codespan_reporting::{diagnostic::Diagnostic, files::SimpleFiles};
|
|||||||
use lalrpop_util::lalrpop_mod;
|
use lalrpop_util::lalrpop_mod;
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
|
pub mod ast;
|
||||||
mod location;
|
mod location;
|
||||||
mod simplify;
|
mod simplify;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
@@ -10,7 +11,7 @@ lalrpop_mod!(
|
|||||||
parser,
|
parser,
|
||||||
"/syntax/parser.rs"
|
"/syntax/parser.rs"
|
||||||
);
|
);
|
||||||
pub mod ast;
|
mod pretty;
|
||||||
mod validate;
|
mod validate;
|
||||||
|
|
||||||
pub use crate::syntax::ast::*;
|
pub use crate::syntax::ast::*;
|
||||||
|
|||||||
@@ -1,59 +1,18 @@
|
|||||||
use crate::syntax::Location;
|
use crate::syntax::Location;
|
||||||
use pretty::{DocAllocator, DocBuilder, Pretty};
|
|
||||||
|
|
||||||
static BINARY_OPERATORS: &[&str] = &["+", "-", "*", "/"];
|
pub static BINARY_OPERATORS: &[&str] = &["+", "-", "*", "/"];
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Program
|
|
||||||
where
|
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
let mut result = allocator.nil();
|
|
||||||
|
|
||||||
for stmt in self.statements.iter() {
|
|
||||||
result = result
|
|
||||||
.append(stmt.pretty(allocator))
|
|
||||||
.append(allocator.text(";"))
|
|
||||||
.append(allocator.hardline());
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Binding(Location, String, Expression),
|
Binding(Location, String, Expression),
|
||||||
Print(Location, String),
|
Print(Location, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Statement
|
|
||||||
where
|
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, 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())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Value(Location, Value),
|
Value(Location, Value),
|
||||||
@@ -61,79 +20,7 @@ pub enum Expression {
|
|||||||
Primitive(Location, String, Vec<Expression>),
|
Primitive(Location, String, Vec<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Expression
|
|
||||||
where
|
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
|
||||||
Expression::Value(_, val) => val.pretty(allocator),
|
|
||||||
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
|
||||||
Expression::Primitive(_, op, exprs) if BINARY_OPERATORS.contains(&op.as_ref()) => {
|
|
||||||
assert_eq!(
|
|
||||||
exprs.len(),
|
|
||||||
2,
|
|
||||||
"Found binary operator with {} components?",
|
|
||||||
exprs.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
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, CommaSep {});
|
|
||||||
call.append(comma_sepped_args.parens())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Number(Option<u8>, i64),
|
Number(Option<u8>, i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Value
|
|
||||||
where
|
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
|
||||||
Value::Number(opt_base, value) => {
|
|
||||||
let value_str = match opt_base {
|
|
||||||
None => format!("{}", value),
|
|
||||||
Some(2) => format!("0b{:b}", value),
|
|
||||||
Some(8) => format!("0o{:o}", value),
|
|
||||||
Some(10) => format!("0d{}", value),
|
|
||||||
Some(16) => format!("0x{:x}", value),
|
|
||||||
Some(_) => format!("!!{:x}!!", value),
|
|
||||||
};
|
|
||||||
|
|
||||||
allocator.text(value_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct CommaSep {}
|
|
||||||
|
|
||||||
impl<'a, D, A> Pretty<'a, D, A> for CommaSep
|
|
||||||
where
|
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
allocator.text(",").append(allocator.space())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
114
src/syntax/pretty.rs
Normal file
114
src/syntax/pretty.rs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
use pretty::{Pretty, DocAllocator, DocBuilder};
|
||||||
|
use crate::syntax::ast::{Program, Statement, Expression, Value, BINARY_OPERATORS};
|
||||||
|
|
||||||
|
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Program
|
||||||
|
where
|
||||||
|
A: 'a,
|
||||||
|
D: ?Sized + DocAllocator<'a, A>,
|
||||||
|
{
|
||||||
|
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
||||||
|
let mut result = allocator.nil();
|
||||||
|
|
||||||
|
for stmt in self.statements.iter() {
|
||||||
|
result = result
|
||||||
|
.append(stmt.pretty(allocator))
|
||||||
|
.append(allocator.text(";"))
|
||||||
|
.append(allocator.hardline());
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Statement
|
||||||
|
where
|
||||||
|
A: 'a,
|
||||||
|
D: ?Sized + DocAllocator<'a, A>,
|
||||||
|
{
|
||||||
|
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, 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())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Expression
|
||||||
|
where
|
||||||
|
A: 'a,
|
||||||
|
D: ?Sized + DocAllocator<'a, A>,
|
||||||
|
{
|
||||||
|
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
||||||
|
match self {
|
||||||
|
Expression::Value(_, val) => val.pretty(allocator),
|
||||||
|
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
||||||
|
Expression::Primitive(_, op, exprs) if BINARY_OPERATORS.contains(&op.as_ref()) => {
|
||||||
|
assert_eq!(
|
||||||
|
exprs.len(),
|
||||||
|
2,
|
||||||
|
"Found binary operator with {} components?",
|
||||||
|
exprs.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
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, CommaSep {});
|
||||||
|
call.append(comma_sepped_args.parens())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Value
|
||||||
|
where
|
||||||
|
A: 'a,
|
||||||
|
D: ?Sized + DocAllocator<'a, A>,
|
||||||
|
{
|
||||||
|
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
||||||
|
match self {
|
||||||
|
Value::Number(opt_base, value) => {
|
||||||
|
let value_str = match opt_base {
|
||||||
|
None => format!("{}", value),
|
||||||
|
Some(2) => format!("0b{:b}", value),
|
||||||
|
Some(8) => format!("0o{:o}", value),
|
||||||
|
Some(10) => format!("0d{}", value),
|
||||||
|
Some(16) => format!("0x{:x}", value),
|
||||||
|
Some(_) => format!("!!{:x}!!", value),
|
||||||
|
};
|
||||||
|
|
||||||
|
allocator.text(value_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct CommaSep {}
|
||||||
|
|
||||||
|
impl<'a, D, A> Pretty<'a, D, A> for CommaSep
|
||||||
|
where
|
||||||
|
A: 'a,
|
||||||
|
D: ?Sized + DocAllocator<'a, A>,
|
||||||
|
{
|
||||||
|
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
||||||
|
allocator.text(",").append(allocator.space())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user