λ Support functions! #5
@@ -30,6 +30,8 @@ target-lexicon = "0.12.14"
|
|||||||
tempfile = "3.10.0"
|
tempfile = "3.10.0"
|
||||||
thiserror = "1.0.57"
|
thiserror = "1.0.57"
|
||||||
anyhow = "1.0.80"
|
anyhow = "1.0.80"
|
||||||
|
tracing = "0.1.40"
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["time", "json", "env-filter"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lalrpop = "0.20.0"
|
lalrpop = "0.20.0"
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ impl<M: Module> Backend<M> {
|
|||||||
true,
|
true,
|
||||||
false,
|
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.module.define_data(data_id, &pt.blank_data())?;
|
||||||
self.defined_symbols
|
self.defined_symbols
|
||||||
.insert(top_level_name, (data_id, pt.into()));
|
.insert(top_level_name, (data_id, pt.into()));
|
||||||
@@ -125,7 +125,7 @@ impl<M: Module> Backend<M> {
|
|||||||
argument_types: Vec<Type>,
|
argument_types: Vec<Type>,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
) -> Result<FuncId, cranelift_module::ModuleError> {
|
) -> Result<FuncId, cranelift_module::ModuleError> {
|
||||||
println!("Declaring {:?} function {}", linkage, name);
|
tracing::info!(linkage = ?linkage, name, "Declaring function");
|
||||||
let basic_signature = Signature {
|
let basic_signature = Signature {
|
||||||
params: argument_types
|
params: argument_types
|
||||||
.iter()
|
.iter()
|
||||||
@@ -148,6 +148,7 @@ impl<M: Module> Backend<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the given function.
|
/// Compile the given function.
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, variables, body))]
|
||||||
pub fn compile_function(
|
pub fn compile_function(
|
||||||
&mut self,
|
&mut self,
|
||||||
variables: &mut HashMap<Variable, ReferenceBuilder>,
|
variables: &mut HashMap<Variable, ReferenceBuilder>,
|
||||||
@@ -156,22 +157,6 @@ impl<M: Module> Backend<M> {
|
|||||||
return_type: Type,
|
return_type: Type,
|
||||||
body: Expression<Type>,
|
body: Expression<Type>,
|
||||||
) -> Result<FuncId, BackendError> {
|
) -> Result<FuncId, BackendError> {
|
||||||
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
|
// reset the next variable counter. this value shouldn't matter; hopefully
|
||||||
// we won't be using close to 2^32 variables!
|
// we won't be using close to 2^32 variables!
|
||||||
self.reset_local_variable_tracker();
|
self.reset_local_variable_tracker();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ struct CommandLineArguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
let args = CommandLineArguments::parse();
|
let args = CommandLineArguments::parse();
|
||||||
let mut compiler = ngr::Compiler::default();
|
let mut compiler = ngr::Compiler::default();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use rustyline::error::ReadlineError;
|
|||||||
use rustyline::DefaultEditor;
|
use rustyline::DefaultEditor;
|
||||||
|
|
||||||
fn main() -> Result<(), BackendError> {
|
fn main() -> Result<(), BackendError> {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
let mut editor = DefaultEditor::new().expect("rustyline works");
|
let mut editor = DefaultEditor::new().expect("rustyline works");
|
||||||
let mut line_no = 0;
|
let mut line_no = 0;
|
||||||
let mut state = ngr::REPL::default();
|
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
|
// it's not clear to me what this could be, but OK
|
||||||
Err(ReadlineError::Io(e)) => {
|
Err(ReadlineError::Io(e)) => {
|
||||||
eprintln!("IO error: {}", e);
|
tracing::error!(error = %e, "IO error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ fn main() -> Result<(), BackendError> {
|
|||||||
// what would cause this, but ...
|
// what would cause this, but ...
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
Err(ReadlineError::Errno(e)) => {
|
Err(ReadlineError::Errno(e)) => {
|
||||||
eprintln!("Unknown syscall error: {}", e);
|
tracing::error!(error = %e, "Unknown syscall.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ fn main() -> Result<(), BackendError> {
|
|||||||
|
|
||||||
// Why on earth are there so many error types?
|
// Why on earth are there so many error types?
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Unknown internal error: {}", e);
|
tracing::error!(error = %e, "Unknown internal error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ fn jit(ir: ngr::ir::Program<ngr::ir::Type>) -> Result<fn(), ngr::backend::Backen
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
let cli = CommandLineArguments::parse();
|
let cli = CommandLineArguments::parse();
|
||||||
let mut file_database = SimpleFiles::new();
|
let mut file_database = SimpleFiles::new();
|
||||||
let mut console = StandardStream::stdout(pretty::termcolor::ColorChoice::Auto);
|
let mut console = StandardStream::stdout(pretty::termcolor::ColorChoice::Auto);
|
||||||
@@ -72,7 +73,7 @@ fn main() {
|
|||||||
|
|
||||||
if cli.interpreter == Interpreter::Syntax {
|
if cli.interpreter == Interpreter::Syntax {
|
||||||
match syntax.eval() {
|
match syntax.eval() {
|
||||||
Err(e) => println!("Evaluation error: {}", e),
|
Err(e) => tracing::error!(error = %e, "Evaluation error"),
|
||||||
Ok(v) => print_result(v),
|
Ok(v) => print_result(v),
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -98,7 +99,7 @@ fn main() {
|
|||||||
|
|
||||||
if cli.interpreter == Interpreter::IR {
|
if cli.interpreter == Interpreter::IR {
|
||||||
match ir.eval() {
|
match ir.eval() {
|
||||||
Err(e) => println!("Evaluation error: {}", e),
|
Err(e) => tracing::error!(error = %e, "Evaluation error"),
|
||||||
Ok(v) => print_result(v),
|
Ok(v) => print_result(v),
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
eval::{PrimOpError, Value},
|
eval::{PrimOpError, Value},
|
||||||
syntax::ConstantType,
|
syntax::ConstantType,
|
||||||
};
|
};
|
||||||
|
use pretty::{Arena, DocAllocator, DocBuilder};
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
@@ -17,19 +18,27 @@ pub enum PrimitiveType {
|
|||||||
I64,
|
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 {
|
impl Display for PrimitiveType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
let arena = Arena::new();
|
||||||
PrimitiveType::Void => write!(f, "void"),
|
let doc = self.pretty(&arena);
|
||||||
PrimitiveType::I8 => write!(f, "i8"),
|
doc.render_fmt(72, f)
|
||||||
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"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
mod arbitrary;
|
mod arbitrary;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod eval;
|
mod eval;
|
||||||
|
mod pretty;
|
||||||
mod strings;
|
mod strings;
|
||||||
mod top_level;
|
mod top_level;
|
||||||
|
|
||||||
|
|||||||
316
src/ir/ast.rs
316
src/ir/ast.rs
@@ -1,13 +1,8 @@
|
|||||||
use crate::{
|
use crate::eval::PrimitiveType;
|
||||||
eval::PrimitiveType,
|
use crate::syntax::{ConstantType, Location};
|
||||||
syntax::{self, ConstantType, Location},
|
|
||||||
util::pretty::{pretty_comma_separated, PrettySymbol},
|
|
||||||
};
|
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
use pretty::{BoxAllocator, DocAllocator, Pretty};
|
|
||||||
use proptest::arbitrary::Arbitrary;
|
use proptest::arbitrary::Arbitrary;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
@@ -58,29 +53,6 @@ pub struct Program<Type> {
|
|||||||
pub(crate) items: Vec<TopLevel<Type>>,
|
pub(crate) items: Vec<TopLevel<Type>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Program<Type>
|
|
||||||
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> {
|
impl Arbitrary for Program<Type> {
|
||||||
type Parameters = ();
|
type Parameters = ();
|
||||||
type Strategy = ProgramGenerator;
|
type Strategy = ProgramGenerator;
|
||||||
@@ -114,35 +86,6 @@ impl<T: Clone + TypeWithVoid + TypeWithFunction> TopLevel<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b TopLevel<Type>
|
|
||||||
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.
|
/// The representation of an expression.
|
||||||
///
|
///
|
||||||
/// Note that expressions, like everything else in this syntax tree,
|
/// Note that expressions, like everything else in this syntax tree,
|
||||||
@@ -196,94 +139,6 @@ impl<Type: Clone + TypeWithVoid> Expression<Type> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Expression<Type>
|
|
||||||
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<Type> {
|
|
||||||
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.
|
/// A type representing the primitives allowed in the language.
|
||||||
///
|
///
|
||||||
/// Having this as an enumeration avoids a lot of "this should not happen"
|
/// 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.
|
/// An expression that is always either a value or a reference.
|
||||||
///
|
///
|
||||||
/// This is the type used to guarantee that we don't nest expressions
|
/// This is the type used to guarantee that we don't nest expressions
|
||||||
@@ -344,19 +178,6 @@ pub enum ValueOrRef<Type> {
|
|||||||
Ref(Location, Type, ArcIntern<String>),
|
Ref(Location, Type, ArcIntern<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b ValueOrRef<Type>
|
|
||||||
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<Type: Clone> ValueOrRef<Type> {
|
impl<Type: Clone> ValueOrRef<Type> {
|
||||||
pub fn type_of(&self) -> Type {
|
pub fn type_of(&self) -> Type {
|
||||||
match self {
|
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<u8>, 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("<void>"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Primitive(PrimitiveType),
|
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<PrimitiveType> for Type {
|
impl From<PrimitiveType> for Type {
|
||||||
fn from(value: PrimitiveType) -> Self {
|
fn from(value: PrimitiveType) -> Self {
|
||||||
Type::Primitive(value)
|
Type::Primitive(value)
|
||||||
@@ -530,55 +267,6 @@ pub enum TypeOrVar {
|
|||||||
Function(Vec<TypeOrVar>, Box<TypeOrVar>),
|
Function(Vec<TypeOrVar>, Box<TypeOrVar>),
|
||||||
}
|
}
|
||||||
|
|
||||||
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, "<function:")?;
|
|
||||||
match args.split_last() {
|
|
||||||
None => 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 {
|
impl Default for TypeOrVar {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TypeOrVar::new()
|
TypeOrVar::new()
|
||||||
|
|||||||
205
src/ir/pretty.rs
Normal file
205
src/ir/pretty.rs
Normal file
@@ -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<Type> {
|
||||||
|
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<Type> {
|
||||||
|
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<Type> {
|
||||||
|
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<Type> {
|
||||||
|
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<u8>, 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("<void>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Type>);
|
||||||
|
derived_display!(TopLevel<Type>);
|
||||||
|
derived_display!(Expression<Type>);
|
||||||
|
derived_display!(Primitive);
|
||||||
|
derived_display!(Type);
|
||||||
|
derived_display!(TypeOrVar);
|
||||||
|
derived_display!(ValueOrRef<Type>);
|
||||||
|
derived_display!(Value);
|
||||||
@@ -106,9 +106,9 @@ impl REPL {
|
|||||||
pub fn process_input(&mut self, line_no: usize, command: String) {
|
pub fn process_input(&mut self, line_no: usize, command: String) {
|
||||||
if let Err(err) = self.process(line_no, command) {
|
if let Err(err) = self.process(line_no, command) {
|
||||||
if let Err(e) = self.emit_diagnostic(Diagnostic::from(err)) {
|
if let Err(e) = self.emit_diagnostic(Diagnostic::from(err)) {
|
||||||
eprintln!(
|
tracing::error!(
|
||||||
"WOAH! System having trouble printing error messages. This is very bad. ({})",
|
error = %e,
|
||||||
e
|
"WOAH! System having trouble printing error messages. This is very bad.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
use crate::syntax::ast::{Expression, Program, Statement, Value};
|
use crate::syntax::ast::{ConstantType, Expression, Program, Statement, TopLevel, Value};
|
||||||
use pretty::{DocAllocator, DocBuilder, Pretty};
|
use crate::util::pretty::{Allocator, derived_display};
|
||||||
|
use pretty::{DocAllocator, DocBuilder};
|
||||||
|
|
||||||
use super::{ConstantType, TopLevel};
|
impl Program {
|
||||||
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
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();
|
let mut result = allocator.nil();
|
||||||
|
|
||||||
for tl in self.items.iter() {
|
for tl in self.items.iter() {
|
||||||
@@ -22,12 +17,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b TopLevel
|
impl TopLevel {
|
||||||
where
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
match self {
|
||||||
TopLevel::Statement(stmt) => stmt.pretty(allocator),
|
TopLevel::Statement(stmt) => stmt.pretty(allocator),
|
||||||
TopLevel::Function(name, arg_names, body) => allocator
|
TopLevel::Function(name, arg_names, body) => allocator
|
||||||
@@ -42,7 +33,7 @@ where
|
|||||||
allocator
|
allocator
|
||||||
.intersperse(
|
.intersperse(
|
||||||
arg_names.iter().map(|x| allocator.text(x.to_string())),
|
arg_names.iter().map(|x| allocator.text(x.to_string())),
|
||||||
CommaSep {},
|
allocator.text(","),
|
||||||
)
|
)
|
||||||
.parens(),
|
.parens(),
|
||||||
)
|
)
|
||||||
@@ -52,12 +43,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Statement
|
impl Statement {
|
||||||
where
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
match self {
|
||||||
Statement::Binding(_, var, expr) => allocator
|
Statement::Binding(_, var, expr) => allocator
|
||||||
.text(var.to_string())
|
.text(var.to_string())
|
||||||
@@ -73,12 +60,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Expression
|
impl Expression {
|
||||||
where
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(_, val) => val.pretty(allocator),
|
Expression::Value(_, val) => val.pretty(allocator),
|
||||||
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
||||||
@@ -102,12 +85,12 @@ where
|
|||||||
Expression::Primitive(_, op, exprs) => {
|
Expression::Primitive(_, op, exprs) => {
|
||||||
let call = allocator.text(op.to_string());
|
let call = allocator.text(op.to_string());
|
||||||
let args = exprs.iter().map(|x| x.pretty(allocator));
|
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())
|
call.append(comma_sepped_args.parens())
|
||||||
}
|
}
|
||||||
Expression::Call(_, fun, args) => {
|
Expression::Call(_, fun, args) => {
|
||||||
let args = args.iter().map(|x| x.pretty(allocator));
|
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())
|
fun.pretty(allocator).append(comma_sepped_args.parens())
|
||||||
}
|
}
|
||||||
Expression::Block(_, stmts) => match stmts.split_last() {
|
Expression::Block(_, stmts) => match stmts.split_last() {
|
||||||
@@ -133,12 +116,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Value
|
impl Value {
|
||||||
where
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
match self {
|
match self {
|
||||||
Value::Number(opt_base, ty, value) => {
|
Value::Number(opt_base, ty, value) => {
|
||||||
let value_str = match opt_base {
|
let value_str = match opt_base {
|
||||||
@@ -171,15 +150,8 @@ fn type_suffix(x: &Option<ConstantType>) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
derived_display!(Program);
|
||||||
pub struct CommaSep {}
|
derived_display!(TopLevel);
|
||||||
|
derived_display!(Statement);
|
||||||
impl<'a, D, A> Pretty<'a, D, A> for CommaSep
|
derived_display!(Expression);
|
||||||
where
|
derived_display!(Value);
|
||||||
A: 'a,
|
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
|
||||||
{
|
|
||||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D, A> {
|
|
||||||
allocator.text(",").append(allocator.space())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,24 +6,8 @@ pub fn finalize_program(
|
|||||||
mut program: Program<TypeOrVar>,
|
mut program: Program<TypeOrVar>,
|
||||||
resolutions: &TypeResolutions,
|
resolutions: &TypeResolutions,
|
||||||
) -> Program<Type> {
|
) -> Program<Type> {
|
||||||
println!("RESOLUTIONS:");
|
|
||||||
for (name, ty) in resolutions.iter() {
|
for (name, ty) in resolutions.iter() {
|
||||||
println!("{} => {}", name, ty);
|
tracing::debug!(name = %name, resolved_type = %ty, "resolved type variable");
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Program {
|
Program {
|
||||||
|
|||||||
@@ -1,49 +1,35 @@
|
|||||||
use internment::ArcIntern;
|
use pretty::Arena;
|
||||||
use pretty::{DocAllocator, Pretty};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub type Allocator<'a> = Arena<'a, ()>;
|
||||||
pub struct PrettySymbol {
|
|
||||||
name: ArcIntern<String>,
|
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<String>> for PrettySymbol {
|
macro_rules! derived_display {
|
||||||
fn from(value: &'a ArcIntern<String>) -> Self {
|
($type: ty) => {
|
||||||
PrettySymbol {
|
impl std::fmt::Display for $type {
|
||||||
name: value.clone(),
|
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
|
// this is a dumb Rust trick to export the functions to the rest
|
||||||
where
|
// of the crate, but not globally.
|
||||||
A: 'a,
|
pub(crate) use pretty_function_type;
|
||||||
D: ?Sized + DocAllocator<'a, A>,
|
pub(crate) use derived_display;
|
||||||
{
|
|
||||||
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<P>,
|
|
||||||
) -> 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, ", ")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user