From e9fbd275a21b3f3c72ecc36e146822b39a70c113 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 2 Mar 2024 21:19:29 -0800 Subject: [PATCH] Clean up pretty printing and work on logging. --- Cargo.toml | 2 + src/backend/into_crane.rs | 21 +-- src/bin/ngrc.rs | 1 + src/bin/ngri.rs | 7 +- src/bin/ngrun.rs | 5 +- src/eval/primtype.rs | 31 ++-- src/ir.rs | 1 + src/ir/ast.rs | 316 +------------------------------------ src/ir/pretty.rs | 205 ++++++++++++++++++++++++ src/repl.rs | 6 +- src/syntax/pretty.rs | 70 +++----- src/type_infer/finalize.rs | 18 +-- src/util/pretty.rs | 72 ++++----- 13 files changed, 295 insertions(+), 460 deletions(-) create mode 100644 src/ir/pretty.rs diff --git a/Cargo.toml b/Cargo.toml index 94a18b6..ad4b96b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ target-lexicon = "0.12.14" tempfile = "3.10.0" thiserror = "1.0.57" anyhow = "1.0.80" +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["time", "json", "env-filter"] } [build-dependencies] lalrpop = "0.20.0" diff --git a/src/backend/into_crane.rs b/src/backend/into_crane.rs index d4053b7..b260927 100644 --- a/src/backend/into_crane.rs +++ b/src/backend/into_crane.rs @@ -83,7 +83,7 @@ impl Backend { true, false, )?; - println!("defining {} with primitive type {}", top_level_name, pt); + tracing::info!(name = %top_level_name, data_type = %pt, "defining top-level data"); self.module.define_data(data_id, &pt.blank_data())?; self.defined_symbols .insert(top_level_name, (data_id, pt.into())); @@ -125,7 +125,7 @@ impl Backend { argument_types: Vec, return_type: Type, ) -> Result { - println!("Declaring {:?} function {}", linkage, name); + tracing::info!(linkage = ?linkage, name, "Declaring function"); let basic_signature = Signature { params: argument_types .iter() @@ -148,6 +148,7 @@ impl Backend { } /// Compile the given function. + #[tracing::instrument(level = "debug", skip(self, variables, body))] pub fn compile_function( &mut self, variables: &mut HashMap, @@ -156,22 +157,6 @@ impl Backend { return_type: Type, body: Expression, ) -> Result { - println!("Compiling function {}", function_name); - { - use pretty::{DocAllocator, Pretty}; - let allocator = pretty::BoxAllocator; - allocator - .text("Function body:") - .append(allocator.hardline()) - .append(body.pretty(&allocator)) - .append(allocator.hardline()) - .1 - .render_colored( - 70, - pretty::termcolor::StandardStream::stdout(pretty::termcolor::ColorChoice::Auto), - ) - .expect("rendering works"); - } // reset the next variable counter. this value shouldn't matter; hopefully // we won't be using close to 2^32 variables! self.reset_local_variable_tracker(); diff --git a/src/bin/ngrc.rs b/src/bin/ngrc.rs index e486ec0..a88f4bd 100644 --- a/src/bin/ngrc.rs +++ b/src/bin/ngrc.rs @@ -14,6 +14,7 @@ struct CommandLineArguments { } fn main() { + tracing_subscriber::fmt::init(); let args = CommandLineArguments::parse(); let mut compiler = ngr::Compiler::default(); diff --git a/src/bin/ngri.rs b/src/bin/ngri.rs index 0558de4..482d81c 100644 --- a/src/bin/ngri.rs +++ b/src/bin/ngri.rs @@ -3,6 +3,7 @@ use rustyline::error::ReadlineError; use rustyline::DefaultEditor; fn main() -> Result<(), BackendError> { + tracing_subscriber::fmt::init(); let mut editor = DefaultEditor::new().expect("rustyline works"); let mut line_no = 0; let mut state = ngr::REPL::default(); @@ -19,7 +20,7 @@ fn main() -> Result<(), BackendError> { // it's not clear to me what this could be, but OK Err(ReadlineError::Io(e)) => { - eprintln!("IO error: {}", e); + tracing::error!(error = %e, "IO error"); break; } @@ -31,7 +32,7 @@ fn main() -> Result<(), BackendError> { // what would cause this, but ... #[cfg(not(windows))] Err(ReadlineError::Errno(e)) => { - eprintln!("Unknown syscall error: {}", e); + tracing::error!(error = %e, "Unknown syscall."); break; } @@ -41,7 +42,7 @@ fn main() -> Result<(), BackendError> { // Why on earth are there so many error types? Err(e) => { - eprintln!("Unknown internal error: {}", e); + tracing::error!(error = %e, "Unknown internal error"); break; } } diff --git a/src/bin/ngrun.rs b/src/bin/ngrun.rs index 4bce462..c40cfbb 100644 --- a/src/bin/ngrun.rs +++ b/src/bin/ngrun.rs @@ -42,6 +42,7 @@ fn jit(ir: ngr::ir::Program) -> Result println!("Evaluation error: {}", e), + Err(e) => tracing::error!(error = %e, "Evaluation error"), Ok(v) => print_result(v), } return; @@ -98,7 +99,7 @@ fn main() { if cli.interpreter == Interpreter::IR { match ir.eval() { - Err(e) => println!("Evaluation error: {}", e), + Err(e) => tracing::error!(error = %e, "Evaluation error"), Ok(v) => print_result(v), } return; diff --git a/src/eval/primtype.rs b/src/eval/primtype.rs index e86ae69..f67768e 100644 --- a/src/eval/primtype.rs +++ b/src/eval/primtype.rs @@ -2,6 +2,7 @@ use crate::{ eval::{PrimOpError, Value}, syntax::ConstantType, }; +use pretty::{Arena, DocAllocator, DocBuilder}; use std::{fmt::Display, str::FromStr}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -17,19 +18,27 @@ pub enum PrimitiveType { I64, } +impl PrimitiveType { + pub fn pretty<'a>(&self, allocator: &'a Arena<'a, ()>) -> DocBuilder<'a, Arena<'a, ()>> { + match self { + PrimitiveType::Void => allocator.text("void"), + PrimitiveType::I8 => allocator.text("i8"), + PrimitiveType::I16 => allocator.text("i16"), + PrimitiveType::I32 => allocator.text("i32"), + PrimitiveType::I64 => allocator.text("i64"), + PrimitiveType::U8 => allocator.text("u8"), + PrimitiveType::U16 => allocator.text("u16"), + PrimitiveType::U32 => allocator.text("u32"), + PrimitiveType::U64 => allocator.text("u64"), + } + } +} + impl Display for PrimitiveType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PrimitiveType::Void => write!(f, "void"), - PrimitiveType::I8 => write!(f, "i8"), - PrimitiveType::I16 => write!(f, "i16"), - PrimitiveType::I32 => write!(f, "i32"), - PrimitiveType::I64 => write!(f, "i64"), - PrimitiveType::U8 => write!(f, "u8"), - PrimitiveType::U16 => write!(f, "u16"), - PrimitiveType::U32 => write!(f, "u32"), - PrimitiveType::U64 => write!(f, "u64"), - } + let arena = Arena::new(); + let doc = self.pretty(&arena); + doc.render_fmt(72, f) } } diff --git a/src/ir.rs b/src/ir.rs index e058e66..48ac76f 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -15,6 +15,7 @@ mod arbitrary; pub mod ast; mod eval; +mod pretty; mod strings; mod top_level; diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 7480483..ae76a95 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -1,13 +1,8 @@ -use crate::{ - eval::PrimitiveType, - syntax::{self, ConstantType, Location}, - util::pretty::{pretty_comma_separated, PrettySymbol}, -}; +use crate::eval::PrimitiveType; +use crate::syntax::{ConstantType, Location}; use internment::ArcIntern; -use pretty::{BoxAllocator, DocAllocator, Pretty}; use proptest::arbitrary::Arbitrary; use std::convert::TryFrom; -use std::fmt; use std::str::FromStr; use std::sync::atomic::AtomicUsize; @@ -58,29 +53,6 @@ pub struct Program { pub(crate) items: Vec>, } -impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Program -where - A: 'a, - D: ?Sized + DocAllocator<'a, A> + 'a, - &'b Type: Pretty<'a, D, A>, - pretty::DocBuilder<'a, D, A>: Clone, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - let mut result = allocator.nil(); - - for stmt in self.items.iter() { - // there's probably a better way to do this, rather than constantly - // adding to the end, but this works. - result = result - .append(stmt.pretty(allocator)) - .append(allocator.text(";")) - .append(allocator.hardline()); - } - - result - } -} - impl Arbitrary for Program { type Parameters = (); type Strategy = ProgramGenerator; @@ -114,35 +86,6 @@ impl TopLevel { } } -impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b TopLevel -where - A: 'a, - D: ?Sized + DocAllocator<'a, A> + 'a, - &'b Type: Pretty<'a, D, A>, - pretty::DocBuilder<'a, D, A>: Clone, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - TopLevel::Function(name, args, _, expr) => allocator - .text("function") - .append(allocator.space()) - .append(allocator.text(name.as_ref().to_string())) - .append(allocator.space()) - .append( - pretty_comma_separated( - allocator, - &args.iter().map(|(x, _)| PrettySymbol::from(x)).collect(), - ) - .parens(), - ) - .append(allocator.space()) - .append(expr.pretty(allocator)), - - TopLevel::Statement(stmt) => stmt.pretty(allocator), - } - } -} - /// The representation of an expression. /// /// Note that expressions, like everything else in this syntax tree, @@ -196,94 +139,6 @@ impl Expression { } } -impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Expression -where - A: 'a, - D: ?Sized + DocAllocator<'a, A> + 'a, - &'b Type: Pretty<'a, D, A>, - pretty::DocBuilder<'a, D, A>: Clone, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - Expression::Atomic(x) => x.pretty(allocator), - Expression::Cast(_, t, e) => allocator - .text("<") - .append(t.pretty(allocator)) - .append(allocator.text(">")) - .append(e.pretty(allocator)), - Expression::Primitive(_, _, op, exprs) if exprs.len() == 1 => { - op.pretty(allocator).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(op.pretty(allocator)) - .append(allocator.space()) - .append(right) - .parens() - } - Expression::Primitive(_, _, op, exprs) => { - allocator.text(format!("!!{:?} with {} arguments!!", op, exprs.len())) - } - Expression::Call(_, _, fun, args) => { - let args = args.iter().map(|x| x.pretty(allocator)); - let comma_sepped_args = - allocator.intersperse(args, crate::syntax::pretty::CommaSep {}); - fun.pretty(allocator).append(comma_sepped_args.parens()) - } - Expression::Block(_, _, exprs) => match exprs.split_last() { - None => allocator.text("()"), - Some((last, &[])) => last.pretty(allocator), - Some((last, start)) => { - let mut result = allocator.text("{").append(allocator.hardline()); - let starts = start.iter().map(|x| { - x.pretty(allocator) - .append(allocator.text(";")) - .append(allocator.hardline()) - .indent(4) - }); - let last = last - .pretty(allocator) - .append(allocator.hardline()) - .indent(4); - - for start in starts { - result = result.append(start); - } - - result.append(last).append(allocator.text("}")) - } - }, - Expression::Print(_, var) => allocator - .text("print") - .append(allocator.space()) - .append(var.pretty(allocator)), - Expression::Bind(_, var, ty, expr) => allocator - .text(var.as_ref().to_string()) - .append(allocator.space()) - .append(allocator.text(":")) - .append(allocator.space()) - .append(ty.pretty(allocator)) - .append(allocator.space()) - .append(allocator.text("=")) - .append(allocator.space()) - .append(expr.pretty(allocator)), - } - } -} - -impl Expression { - pub fn to_pretty(&self) -> String { - let arena = pretty::Arena::<()>::new(); - let doc = self.pretty(&arena); - let mut output_bytes = Vec::new(); - doc.render(72, &mut output_bytes).unwrap(); - String::from_utf8(output_bytes).expect("pretty generates valid utf-8") - } -} - /// A type representing the primitives allowed in the language. /// /// Having this as an enumeration avoids a lot of "this should not happen" @@ -312,27 +167,6 @@ impl FromStr for Primitive { } } -impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Primitive -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - Primitive::Plus => allocator.text("+"), - Primitive::Minus => allocator.text("-"), - Primitive::Times => allocator.text("*"), - Primitive::Divide => allocator.text("/"), - } - } -} - -impl fmt::Display for Primitive { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - <&Primitive as Pretty<'_, BoxAllocator, ()>>::pretty(self, &BoxAllocator).render_fmt(72, f) - } -} - /// An expression that is always either a value or a reference. /// /// This is the type used to guarantee that we don't nest expressions @@ -344,19 +178,6 @@ pub enum ValueOrRef { Ref(Location, Type, ArcIntern), } -impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b ValueOrRef -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - ValueOrRef::Value(_, _, v) => v.pretty(allocator), - ValueOrRef::Ref(_, _, v) => allocator.text(v.as_ref().to_string()), - } - } -} - impl ValueOrRef { pub fn type_of(&self) -> Type { match self { @@ -408,50 +229,6 @@ impl Value { } } -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) -> pretty::DocBuilder<'a, D, A> { - let pretty_internal = |opt_base: &Option, x, t| { - syntax::Value::Number(*opt_base, Some(t), x).pretty(allocator) - }; - - let pretty_internal_signed = |opt_base, x: i64, t| { - let base = pretty_internal(opt_base, x.unsigned_abs(), t); - - allocator.text("-").append(base) - }; - - match self { - Value::I8(opt_base, value) => { - pretty_internal_signed(opt_base, *value as i64, ConstantType::I8) - } - Value::I16(opt_base, value) => { - pretty_internal_signed(opt_base, *value as i64, ConstantType::I16) - } - Value::I32(opt_base, value) => { - pretty_internal_signed(opt_base, *value as i64, ConstantType::I32) - } - Value::I64(opt_base, value) => { - pretty_internal_signed(opt_base, *value, ConstantType::I64) - } - Value::U8(opt_base, value) => { - pretty_internal(opt_base, *value as u64, ConstantType::U8) - } - Value::U16(opt_base, value) => { - pretty_internal(opt_base, *value as u64, ConstantType::U16) - } - Value::U32(opt_base, value) => { - pretty_internal(opt_base, *value as u64, ConstantType::U32) - } - Value::U64(opt_base, value) => pretty_internal(opt_base, *value, ConstantType::U64), - Value::Void => allocator.text(""), - } - } -} - #[derive(Clone, Debug, Eq, PartialEq)] pub enum Type { Primitive(PrimitiveType), @@ -466,46 +243,6 @@ impl Type { } } -impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Type -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - Type::Primitive(pt) => allocator.text(format!("{}", pt)), - Type::Function(args, rettype) => { - pretty_comma_separated(allocator, &args.iter().collect()) - .parens() - .append(allocator.space()) - .append(allocator.text("->")) - .append(allocator.space()) - .append(rettype.pretty(allocator)) - } - } - } -} - -impl fmt::Display for Type { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Type::Primitive(pt) => pt.fmt(f), - Type::Function(args, ret) => { - write!(f, "(")?; - let mut argiter = args.iter().peekable(); - while let Some(arg) = argiter.next() { - arg.fmt(f)?; - if argiter.peek().is_some() { - write!(f, ",")?; - } - } - write!(f, "->")?; - ret.fmt(f) - } - } - } -} - impl From for Type { fn from(value: PrimitiveType) -> Self { Type::Primitive(value) @@ -530,55 +267,6 @@ pub enum TypeOrVar { Function(Vec, Box), } -impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b TypeOrVar -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - match self { - TypeOrVar::Primitive(x) => allocator.text(format!("{}", x)), - TypeOrVar::Variable(_, x) => allocator.text(x.to_string()), - TypeOrVar::Function(args, rettype) => { - pretty_comma_separated(allocator, &args.iter().collect()) - .parens() - .append(allocator.space()) - .append(allocator.text("->")) - .append(allocator.space()) - .append(rettype.pretty(allocator)) - } - } - } -} - -impl fmt::Display for TypeOrVar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TypeOrVar::Primitive(x) => x.fmt(f), - TypeOrVar::Variable(_, v) => write!(f, "{}", v), - TypeOrVar::Function(args, rettype) => { - write!(f, " write!(f, "()")?, - Some((single, &[])) => { - write!(f, "({})", single)?; - } - Some((last_one, rest)) => { - write!(f, "(")?; - for arg in rest.iter() { - write!(f, "{}, ", arg)?; - } - write!(f, "{})", last_one)?; - } - } - write!(f, "->")?; - rettype.fmt(f)?; - write!(f, ">") - } - } - } -} - impl Default for TypeOrVar { fn default() -> Self { TypeOrVar::new() diff --git a/src/ir/pretty.rs b/src/ir/pretty.rs new file mode 100644 index 0000000..7b948fe --- /dev/null +++ b/src/ir/pretty.rs @@ -0,0 +1,205 @@ +use crate::ir::{Expression, Primitive, Program, TopLevel, Type, TypeOrVar, Value, ValueOrRef}; +use crate::syntax::{self, ConstantType}; +use crate::util::pretty::{Allocator, pretty_function_type, derived_display}; +use pretty::{Arena, DocAllocator, DocBuilder}; + +impl Program { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + allocator + .intersperse( + self.items.iter().map(|x| x.pretty(allocator)), + allocator.line(), + ) + .align() + } +} + +impl TopLevel { + pub fn pretty<'a>( + &self, + allocator: &'a Arena<'a, ()>, + ) -> pretty::DocBuilder<'a, Arena<'a, ()>, ()> { + match self { + TopLevel::Function(name, args, _, expr) => allocator + .text("function") + .append(allocator.space()) + .append(allocator.text(name.as_ref().to_string())) + .append(allocator.space()) + .append( + allocator + .intersperse( + args.iter().map(|(x, _)| allocator.text(x.to_string())), + allocator.text(","), + ) + .parens(), + ) + .append(allocator.space()) + .append(expr.pretty(allocator)), + + TopLevel::Statement(stmt) => stmt.pretty(allocator), + } + } +} + +impl Expression { + pub fn pretty<'a>( + &self, + allocator: &'a Arena<'a, ()>, + ) -> pretty::DocBuilder<'a, Arena<'a, ()>, ()> { + match self { + Expression::Atomic(x) => x.pretty(allocator), + Expression::Cast(_, t, e) => allocator + .text("<") + .append(t.pretty(allocator)) + .append(allocator.text(">")) + .append(e.pretty(allocator)), + Expression::Primitive(_, _, op, exprs) if exprs.len() == 1 => { + op.pretty(allocator).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(op.pretty(allocator)) + .append(allocator.space()) + .append(right) + .parens() + } + Expression::Primitive(_, _, op, exprs) => { + allocator.text(format!("!!{:?} with {} arguments!!", op, exprs.len())) + } + 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(_, _, exprs) => match exprs.split_last() { + None => allocator.text("()"), + Some((last, &[])) => last.pretty(allocator), + Some((last, start)) => { + let mut result = allocator.text("{").append(allocator.hardline()); + let starts = start.iter().map(|x| { + x.pretty(allocator) + .append(allocator.text(";")) + .append(allocator.hardline()) + .indent(4) + }); + let last = last + .pretty(allocator) + .append(allocator.hardline()) + .indent(4); + + for start in starts { + result = result.append(start); + } + + result.append(last).append(allocator.text("}")) + } + }, + Expression::Print(_, var) => allocator + .text("print") + .append(allocator.space()) + .append(var.pretty(allocator)), + Expression::Bind(_, var, ty, expr) => allocator + .text(var.as_ref().to_string()) + .append(allocator.space()) + .append(allocator.text(":")) + .append(allocator.space()) + .append(ty.pretty(allocator)) + .append(allocator.space()) + .append(allocator.text("=")) + .append(allocator.space()) + .append(expr.pretty(allocator)), + } + } +} + +impl Primitive { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + match self { + Primitive::Plus => allocator.text("+"), + Primitive::Minus => allocator.text("-"), + Primitive::Times => allocator.text("*"), + Primitive::Divide => allocator.text("/"), + } + } +} + +impl ValueOrRef { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + match self { + ValueOrRef::Value(_, _, v) => v.pretty(allocator), + ValueOrRef::Ref(_, _, v) => allocator.text(v.as_ref().to_string()), + } + } +} + +impl Value { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + let pretty_internal = |opt_base: &Option, x, t| { + syntax::Value::Number(*opt_base, Some(t), x).pretty(allocator) + }; + + let pretty_internal_signed = |opt_base, x: i64, t| { + let base = pretty_internal(opt_base, x.unsigned_abs(), t); + + allocator.text("-").append(base) + }; + + match self { + Value::I8(opt_base, value) => { + pretty_internal_signed(opt_base, *value as i64, ConstantType::I8) + } + Value::I16(opt_base, value) => { + pretty_internal_signed(opt_base, *value as i64, ConstantType::I16) + } + Value::I32(opt_base, value) => { + pretty_internal_signed(opt_base, *value as i64, ConstantType::I32) + } + Value::I64(opt_base, value) => { + pretty_internal_signed(opt_base, *value, ConstantType::I64) + } + Value::U8(opt_base, value) => { + pretty_internal(opt_base, *value as u64, ConstantType::U8) + } + Value::U16(opt_base, value) => { + pretty_internal(opt_base, *value as u64, ConstantType::U16) + } + Value::U32(opt_base, value) => { + pretty_internal(opt_base, *value as u64, ConstantType::U32) + } + Value::U64(opt_base, value) => pretty_internal(opt_base, *value, ConstantType::U64), + Value::Void => allocator.text(""), + } + } +} + +impl Type { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + match self { + Type::Function(args, rettype) => pretty_function_type!(allocator, args, rettype), + Type::Primitive(prim) => prim.pretty(allocator), + } + } +} + +impl TypeOrVar { + pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> { + match self { + TypeOrVar::Function(args, rettype) => pretty_function_type!(allocator, args, rettype), + TypeOrVar::Primitive(prim) => prim.pretty(allocator), + TypeOrVar::Variable(_, name) => allocator.text(name.to_string()), + } + } +} + +derived_display!(Program); +derived_display!(TopLevel); +derived_display!(Expression); +derived_display!(Primitive); +derived_display!(Type); +derived_display!(TypeOrVar); +derived_display!(ValueOrRef); +derived_display!(Value); diff --git a/src/repl.rs b/src/repl.rs index 7d90a50..1fbd501 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -106,9 +106,9 @@ impl REPL { pub fn process_input(&mut self, line_no: usize, command: String) { if let Err(err) = self.process(line_no, command) { if let Err(e) = self.emit_diagnostic(Diagnostic::from(err)) { - eprintln!( - "WOAH! System having trouble printing error messages. This is very bad. ({})", - e + tracing::error!( + error = %e, + "WOAH! System having trouble printing error messages. This is very bad.", ); } } diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs index 6cafc43..c4c1a56 100644 --- a/src/syntax/pretty.rs +++ b/src/syntax/pretty.rs @@ -1,14 +1,9 @@ -use crate::syntax::ast::{Expression, Program, Statement, Value}; -use pretty::{DocAllocator, DocBuilder, Pretty}; +use crate::syntax::ast::{ConstantType, Expression, Program, Statement, TopLevel, Value}; +use crate::util::pretty::{Allocator, derived_display}; +use pretty::{DocAllocator, DocBuilder}; -use super::{ConstantType, TopLevel}; - -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> { +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() { @@ -22,12 +17,8 @@ where } } -impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b TopLevel -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> { +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 @@ -42,7 +33,7 @@ where allocator .intersperse( arg_names.iter().map(|x| allocator.text(x.to_string())), - CommaSep {}, + allocator.text(","), ) .parens(), ) @@ -52,12 +43,8 @@ where } } -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> { +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()) @@ -73,12 +60,8 @@ where } } -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> { +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()), @@ -102,12 +85,12 @@ where 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 {}); + 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, CommaSep {}); + let comma_sepped_args = allocator.intersperse(args, allocator.text(",")); fun.pretty(allocator).append(comma_sepped_args.parens()) } Expression::Block(_, stmts) => match stmts.split_last() { @@ -133,12 +116,8 @@ where } } -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> { +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 { @@ -171,15 +150,8 @@ fn type_suffix(x: &Option) -> &'static str { } } -#[derive(Clone, Copy)] -pub 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()) - } -} +derived_display!(Program); +derived_display!(TopLevel); +derived_display!(Statement); +derived_display!(Expression); +derived_display!(Value); \ No newline at end of file diff --git a/src/type_infer/finalize.rs b/src/type_infer/finalize.rs index 59aecf3..3765946 100644 --- a/src/type_infer/finalize.rs +++ b/src/type_infer/finalize.rs @@ -6,24 +6,8 @@ pub fn finalize_program( mut program: Program, resolutions: &TypeResolutions, ) -> Program { - println!("RESOLUTIONS:"); for (name, ty) in resolutions.iter() { - println!("{} => {}", name, ty); - } - println!("PROGRAM:"); - { - use pretty::{DocAllocator, Pretty}; - let allocator = pretty::BoxAllocator; - allocator - .text("---------------") - .append(allocator.hardline()) - .append(program.pretty(&allocator)) - .1 - .render_colored( - 70, - pretty::termcolor::StandardStream::stdout(pretty::termcolor::ColorChoice::Auto), - ) - .expect("rendering works"); + tracing::debug!(name = %name, resolved_type = %ty, "resolved type variable"); } Program { diff --git a/src/util/pretty.rs b/src/util/pretty.rs index 2cfa55e..1816dae 100644 --- a/src/util/pretty.rs +++ b/src/util/pretty.rs @@ -1,49 +1,35 @@ -use internment::ArcIntern; -use pretty::{DocAllocator, Pretty}; +use pretty::Arena; -#[derive(Clone)] -pub struct PrettySymbol { - name: ArcIntern, +pub type Allocator<'a> = Arena<'a, ()>; + +macro_rules! pretty_function_type { + ($allocator: ident, $args: ident, $rettype: ident) => { + $allocator + .intersperse( + $args.iter().map(|x| x.pretty($allocator)), + $allocator.text(","), + ) + .parens() + .append($allocator.space()) + .append($allocator.text("->")) + .append($allocator.space()) + .append($rettype.pretty($allocator)) + }; } -impl<'a> From<&'a ArcIntern> for PrettySymbol { - fn from(value: &'a ArcIntern) -> Self { - PrettySymbol { - name: value.clone(), +macro_rules! derived_display { + ($type: ty) => { + impl std::fmt::Display for $type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let arena = pretty::Arena::new(); + let doc = self.pretty(&arena); + doc.render_fmt(732, f) + } } - } + }; } -impl<'a, D, A> Pretty<'a, D, A> for PrettySymbol -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - allocator.text(self.name.as_ref().to_string()) - } -} - -impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b PrettySymbol -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, -{ - fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { - allocator.text(self.name.as_ref().to_string()) - } -} - -#[allow(clippy::ptr_arg)] -pub fn pretty_comma_separated<'a, D, A, P>( - allocator: &'a D, - args: &Vec

, -) -> pretty::DocBuilder<'a, D, A> -where - A: 'a, - D: ?Sized + DocAllocator<'a, A>, - P: Pretty<'a, D, A> + Clone, -{ - let individuals = args.iter().map(|x| x.clone().pretty(allocator)); - allocator.intersperse(individuals, ", ") -} +// this is a dumb Rust trick to export the functions to the rest +// of the crate, but not globally. +pub(crate) use pretty_function_type; +pub(crate) use derived_display; \ No newline at end of file