diff --git a/cl-ast/src/ast_impl.rs b/cl-ast/src/ast_impl.rs index b71de7a..6c35567 100644 --- a/cl-ast/src/ast_impl.rs +++ b/cl-ast/src/ast_impl.rs @@ -563,106 +563,6 @@ mod display { } } -pub mod format { - //! Code formatting for the [AST](super::super) - - use std::{ - io::{Result, Write as IoWrite}, - ops::{Deref, DerefMut}, - }; - - /// Trait which adds a function to [Writers](IoWrite) to turn them into [Prettifier] - pub trait Pretty { - /// Indents code according to the number of matched curly braces - fn pretty(self) -> Prettifier<'static, Self> - where Self: IoWrite + Sized; - } - impl Pretty for W { - fn pretty(self) -> Prettifier<'static, Self> - where Self: IoWrite + Sized { - Prettifier::new(self) - } - } - - pub struct Prettifier<'i, T: IoWrite> { - level: isize, - indent: &'i str, - writer: T, - } - impl<'i, W: IoWrite> Prettifier<'i, W> { - pub fn new(writer: W) -> Self { - Self { level: 0, indent: " ", writer } - } - pub fn with_indent(indent: &'i str, writer: W) -> Self { - Self { level: 0, indent, writer } - } - pub fn indent<'scope>(&'scope mut self) -> Indent<'scope, 'i, W> { - Indent::new(self) - } - fn write_indentation(&mut self) -> Result { - let Self { level, indent, writer } = self; - let mut count = 0; - for _ in 0..*level { - count += writer.write(indent.as_bytes())?; - } - Ok(count) - } - } - impl From for Prettifier<'static, W> { - fn from(value: W) -> Self { - Self::new(value) - } - } - impl<'i, W: IoWrite> IoWrite for Prettifier<'i, W> { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let mut size = 0; - for buf in buf.split_inclusive(|b| b"{}".contains(b)) { - match buf.last() { - Some(b'{') => self.level += 1, - Some(b'}') => self.level -= 1, - _ => (), - } - for buf in buf.split_inclusive(|b| b'\n' == *b) { - size += self.writer.write(buf)?; - if let Some(b'\n') = buf.last() { - self.write_indentation()?; - } - } - } - Ok(size) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.writer.flush() - } - } - - pub struct Indent<'scope, 'i, T: IoWrite> { - formatter: &'scope mut Prettifier<'i, T>, - } - impl<'s, 'i, T: IoWrite> Indent<'s, 'i, T> { - pub fn new(formatter: &'s mut Prettifier<'i, T>) -> Self { - formatter.level += 1; - Self { formatter } - } - } - impl<'s, 'i, T: IoWrite> Deref for Indent<'s, 'i, T> { - type Target = Prettifier<'i, T>; - fn deref(&self) -> &Self::Target { - self.formatter - } - } - impl<'s, 'i, T: IoWrite> DerefMut for Indent<'s, 'i, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.formatter - } - } - impl<'s, 'i, T: IoWrite> Drop for Indent<'s, 'i, T> { - fn drop(&mut self) { - self.formatter.level -= 1; - } - } -} mod convert { //! Converts between major enums and enum variants diff --git a/cl-ast/src/format.rs b/cl-ast/src/format.rs new file mode 100644 index 0000000..070fa4b --- /dev/null +++ b/cl-ast/src/format.rs @@ -0,0 +1,106 @@ +use std::{ + fmt::{Result as FmtResult, Write as FmtWrite}, + io::{Result as IoResult, Write as IoWrite}, +}; + +/// Trait which adds a function to [fmt Writers](FmtWrite) to turn them into [Prettifier] +pub trait FmtPretty: FmtWrite { + /// Indents code according to the number of matched curly braces + fn pretty(self) -> Prettifier<'static, Self> + where Self: Sized { + Prettifier::new(self) + } +} +/// Trait which adds a function to [io Writers](IoWrite) to turn them into [Prettifier] +pub trait IoPretty: IoWrite { + /// Indents code according to the number of matched curly braces + fn pretty(self) -> Prettifier<'static, Self> + where Self: Sized; +} +impl FmtPretty for W {} +impl IoPretty for W { + fn pretty(self) -> Prettifier<'static, Self> { + Prettifier::new(self) + } +} + +/// Intercepts calls to either [std::io::Write] or [std::fmt::Write], +/// and inserts indentation between matched parentheses +pub struct Prettifier<'i, T: ?Sized> { + level: isize, + indent: &'i str, + writer: T, +} + +impl<'i, W> Prettifier<'i, W> { + pub fn new(writer: W) -> Self { + Self { level: 0, indent: " ", writer } + } + pub fn with_indent(indent: &'i str, writer: W) -> Self { + Self { level: 0, indent, writer } + } +} + +impl<'i, W: FmtWrite> Prettifier<'i, W> { + #[inline] + fn fmt_write_indentation(&mut self) -> FmtResult { + let Self { level, indent, writer } = self; + for _ in 0..*level { + writer.write_str(indent)?; + } + Ok(()) + } +} +impl<'i, W: IoWrite> Prettifier<'i, W> { + pub fn io_write_indentation(&mut self) -> IoResult { + let Self { level, indent, writer } = self; + let mut count = 0; + for _ in 0..*level { + count += writer.write(indent.as_bytes())?; + } + Ok(count) + } +} + +impl<'i, W: FmtWrite> FmtWrite for Prettifier<'i, W> { + fn write_str(&mut self, s: &str) -> FmtResult { + for s in s.split_inclusive(['{', '}']) { + match s.as_bytes().last() { + Some(b'{') => self.level += 1, + Some(b'}') => self.level -= 1, + _ => (), + } + for s in s.split_inclusive('\n') { + self.writer.write_str(s)?; + if let Some(b'\n') = s.as_bytes().last() { + self.fmt_write_indentation()?; + } + } + } + Ok(()) + } +} + +impl<'i, W: IoWrite> IoWrite for Prettifier<'i, W> { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let mut size = 0; + for buf in buf.split_inclusive(|b| b"{}".contains(b)) { + match buf.last() { + Some(b'{') => self.level += 1, + Some(b'}') => self.level -= 1, + _ => (), + } + for buf in buf.split_inclusive(|b| b'\n' == *b) { + size += self.writer.write(buf)?; + if let Some(b'\n') = buf.last() { + self.io_write_indentation()?; + } + } + } + Ok(size) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.writer.flush() + } +} diff --git a/cl-ast/src/lib.rs b/cl-ast/src/lib.rs index 10ea63e..0005c9a 100644 --- a/cl-ast/src/lib.rs +++ b/cl-ast/src/lib.rs @@ -15,6 +15,7 @@ use cl_structures::span::*; pub mod ast_impl; +pub mod format; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum Mutability { diff --git a/cl-repl/src/lib.rs b/cl-repl/src/lib.rs index 7892291..d8c2f92 100644 --- a/cl-repl/src/lib.rs +++ b/cl-repl/src/lib.rs @@ -84,7 +84,7 @@ pub mod program { env::Environment, error::IResult, interpret::Interpret, temp_type_impl::ConValue, }; - use cl_ast::{self as ast, ast_impl::format::Pretty}; + use cl_ast::{self as ast, format::*}; use cl_lexer::Lexer; use cl_parser::{error::PResult, Parser}; // use conlang::resolver::{error::TyResult, Resolver};