Skip to content

Commit

Permalink
wip: mermaid
Browse files Browse the repository at this point in the history
  • Loading branch information
jeertmans committed Jun 10, 2024
1 parent 640882a commit 148db94
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 1 deletion.
4 changes: 4 additions & 0 deletions logos-codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ rstest = "0.18.2"
[features]
# Enables debug messages
debug = []
# Enable mermaid diagram generation
mermaid = []
# Enables debug messages using mermaid diagrams
mermaid-debug = ["debug", "mermaid"]

[lib]
bench = false
Expand Down
209 changes: 208 additions & 1 deletion logos-codegen/src/graph/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Debug for NodeId {
}

/// We don't need debug impls in release builds
// #[cfg(test)]
#[cfg(debug)]
mod debug {
use super::*;
use crate::graph::rope::Miss;
Expand Down Expand Up @@ -93,6 +93,7 @@ mod debug {
}

impl<T: Debug> Debug for Graph<T> {
#[cfg(not(mermaid-debug))]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entries = self
.nodes()
Expand All @@ -102,6 +103,211 @@ mod debug {

f.debug_map().entries(entries).finish()
}
#[cfg(mermaid-debug)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use super::mermaid::Mermaid;

write!(f, self.mermaid())
writeln!(f, "```mermaid")?;
writeln!(f, "flowchart LR")?;

let entries = self
.nodes()
.iter()
.enumerate()
.filter_map(|(i, n)| n.as_ref().map(|n| (i, n)));

for (i, _) in entries.iter() {
writeln!(f, "\t{i} ({i})")?;
}

write!(f, "```")?;
}
}

struct Arm<T, U>(T, U);

impl<T, U> Debug for Arm<T, U>
where
T: Display,
U: Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ⇒ {}", self.0, self.1)
}
}

impl Debug for Fork {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut list = f.debug_set();

for (range, then) in self.branches() {
list.entry(&Arm(range, then));
}
if let Some(id) = self.miss {
list.entry(&Arm('_', id));
}

list.finish()
}
}

impl Display for Miss {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Miss::First(id) => Display::fmt(id, f),
Miss::Any(id) => write!(f, "{}*", id),
Miss::None => f.write_str("n/a"),
}
}
}

impl Debug for Rope {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Write;

let mut rope = String::with_capacity(self.pattern.len());
for range in self.pattern.iter() {
write!(rope, "{}", range)?;
}

match self.miss.is_none() {
false => {
let mut list = f.debug_list();

list.entry(&Arm(rope, self.then));
list.entry(&Arm('_', self.miss));

list.finish()
}
true => Arm(rope, self.then).fmt(f),
}
}
}

impl PartialEq for Fork {
fn eq(&self, other: &Self) -> bool {
self.miss == other.miss && self.branches().eq(other.branches())
}
}

impl<T: Debug> Debug for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Node::Fork(fork) => fork.fmt(f),
Node::Rope(rope) => rope.fmt(f),
Node::Leaf(leaf) => leaf.fmt(f),
}
}
}

use std::ops::RangeInclusive;

impl From<RangeInclusive<u8>> for Range {
fn from(range: RangeInclusive<u8>) -> Range {
Range {
start: *range.start(),
end: *range.end(),
}
}
}

impl From<RangeInclusive<char>> for Range {
fn from(range: RangeInclusive<char>) -> Range {
Range {
start: *range.start() as u8,
end: *range.end() as u8,
}
}
}

impl<T> PartialEq<Rope> for Node<T> {
fn eq(&self, other: &Rope) -> bool {
match self {
Node::Rope(rope) => rope == other,
_ => false,
}
}
}

impl<T> PartialEq<Fork> for Node<T> {
fn eq(&self, other: &Fork) -> bool {
match self {
Node::Fork(fork) => fork == other,
_ => false,
}
}
}
}


#[cfg(mermaid)]
mod mermaid {
use super::*;
use crate::graph::rope::Miss;
use crate::graph::Disambiguate;
use std::cmp::{Ord, Ordering};

trait Mermaid {
fn write_mermaid(&self, buf: &fmt::Write) -> fmt::Result;
}

impl Disambiguate for &str {
fn cmp(left: &&str, right: &&str) -> Ordering {
Ord::cmp(left, right)
}
}

impl Debug for Range {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Range { start, end } = *self;

if start != end || !is_ascii(start) {
f.write_str("[")?;
}
match is_ascii(start) {
true => write!(f, "{}", start as char),
false => write!(f, "{:02X}", start),
}?;
if start != end {
match is_ascii(end) {
true => write!(f, "-{}]", end as char),
false => write!(f, "-{:02X}]", end),
}?;
} else if !is_ascii(start) {
f.write_str("]")?;
}
Ok(())
}
}

impl Display for Range {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Range as Debug>::fmt(self, f)
}
}

impl<T: Debug> Mermaid for Graph<T> {
fn write_mermaid(&self, buf: &mut fmt::Write) -> fmt::Result {
writeln!(f, "```mermaid")?;
writeln!(f, "flowchart LR")?;

let entries = self
.nodes()
.iter()
.enumerate()
.filter_map(|(i, n)| n.as_ref().map(|n| (i, n)));

for (i, _) in entries.iter() {
writeln!(f, "\t{i} ({i})")?;
}

for (i, _) in entries.iter() {
writeln!(f, "\t{i} ({i})")?;
}

write!(f, "```")?;
}
}

struct Arm<T, U>(T, U);
Expand All @@ -112,6 +318,7 @@ mod debug {
U: Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(buf, "", )
write!(f, "{} ⇒ {}", self.0, self.1)
}
}
Expand Down

0 comments on commit 148db94

Please sign in to comment.