use crate::{
ops::TypedOp as Op,
prelude::*,
run::Lab,
util::{array_vec, deref, maybe_grow},
};
use alloc::collections::BTreeMap;
use arrayvec::ArrayVec;
use core::str::FromStr;
use ordered_float::OrderedFloat;
use TSPL::{new_parser, Parser};
#[derive(Clone, Hash, PartialEq, Eq, Debug, Default)]
pub struct Book {
pub nets: BTreeMap<String, Net>,
}
deref!(Book => self.nets: BTreeMap<String, Net>);
#[derive(Clone, Hash, PartialEq, Eq, Debug, Default)]
pub struct Net {
pub root: Tree,
pub redexes: Vec<(Tree, Tree)>,
}
#[derive(Hash, PartialEq, Eq, Debug, Default)]
pub enum Tree {
#[default]
Era,
Int { val: i64 },
F32 { val: OrderedFloat<f32> },
Ref { nam: String },
Ctr {
lab: Lab,
ports: Vec<Tree>,
},
Op {
op: Op,
rhs: Box<Tree>,
out: Box<Tree>,
},
Mat {
zero: Box<Tree>,
succ: Box<Tree>,
out: Box<Tree>,
},
Adt {
lab: Lab,
variant_index: usize,
variant_count: usize,
fields: Vec<Tree>,
},
Var { nam: String },
}
pub const MAX_ARITY: usize = 8;
pub const MAX_ADT_VARIANTS: usize = MAX_ARITY - 1;
pub const MAX_ADT_FIELDS: usize = MAX_ARITY - 1;
impl Net {
pub fn trees(&self) -> impl Iterator<Item = &Tree> {
iter::once(&self.root).chain(self.redexes.iter().flat_map(|(x, y)| [x, y]))
}
pub fn trees_mut(&mut self) -> impl Iterator<Item = &mut Tree> {
iter::once(&mut self.root).chain(self.redexes.iter_mut().flat_map(|(x, y)| [x, y]))
}
}
impl Tree {
#[inline(always)]
pub fn children(&self) -> impl ExactSizeIterator + DoubleEndedIterator<Item = &Tree> {
ArrayVec::<_, MAX_ARITY>::into_iter(match self {
Tree::Era | Tree::Int { .. } | Tree::F32 { .. } | Tree::Ref { .. } | Tree::Var { .. } => {
array_vec::from_array([])
}
Tree::Ctr { ports, .. } => array_vec::from_iter(ports),
Tree::Op { rhs, out, .. } => array_vec::from_array([rhs, out]),
Tree::Mat { zero, succ, out } => array_vec::from_array([zero, succ, out]),
Tree::Adt { fields, .. } => array_vec::from_iter(fields),
})
}
#[inline(always)]
pub fn children_mut(&mut self) -> impl ExactSizeIterator + DoubleEndedIterator<Item = &mut Tree> {
ArrayVec::<_, MAX_ARITY>::into_iter(match self {
Tree::Era | Tree::Int { .. } | Tree::F32 { .. } | Tree::Ref { .. } | Tree::Var { .. } => {
array_vec::from_array([])
}
Tree::Ctr { ports, .. } => array_vec::from_iter(ports),
Tree::Op { rhs, out, .. } => array_vec::from_array([rhs, out]),
Tree::Mat { zero, succ, out } => array_vec::from_array([zero, succ, out]),
Tree::Adt { fields, .. } => array_vec::from_iter(fields),
})
}
pub(crate) fn lab(&self) -> Option<Lab> {
match self {
Tree::Ctr { lab, ports } if ports.len() >= 2 => Some(*lab),
Tree::Adt { lab, .. } => Some(*lab),
_ => None,
}
}
pub fn legacy_mat(mut arms: Tree, out: Tree) -> Option<Tree> {
let Tree::Ctr { lab: 0, ports } = &mut arms else { None? };
let ports = mem::take(ports);
let Ok([zero, succ]) = <[_; 2]>::try_from(ports) else { None? };
let zero = Box::new(zero);
let succ = Box::new(succ);
Some(Tree::Mat { zero, succ, out: Box::new(out) })
}
}
new_parser!(HvmcParser);
impl<'i> HvmcParser<'i> {
fn parse_book(&mut self) -> Result<Book, String> {
maybe_grow(move || {
let mut book = BTreeMap::new();
while self.consume("@").is_ok() {
let name = self.parse_name()?;
self.consume("=")?;
let net = self.parse_net()?;
book.insert(name, net);
}
Ok(Book { nets: book })
})
}
fn parse_net(&mut self) -> Result<Net, String> {
let mut redexes = Vec::new();
let root = self.parse_tree()?;
while self.consume("&").is_ok() {
let tree1 = self.parse_tree()?;
self.consume("~")?;
let tree2 = self.parse_tree()?;
redexes.push((tree1, tree2));
}
Ok(Net { root, redexes })
}
fn parse_tree(&mut self) -> Result<Tree, String> {
maybe_grow(move || {
self.skip_trivia();
match self.peek_one() {
Some('*') => {
self.advance_one();
Ok(Tree::Era)
}
Some(char @ ('(' | '[' | '{')) => {
self.advance_one();
let lab = match char {
'(' => 0,
'[' => 1,
'{' => self.parse_u64()? as Lab,
_ => unreachable!(),
};
let close = match char {
'(' => ')',
'[' => ']',
'{' => '}',
_ => unreachable!(),
};
self.skip_trivia();
if self.peek_one().is_some_and(|x| x == ':') {
self.advance_one();
let variant_index = self.parse_u64()?;
self.consume(":")?;
let variant_count = self.parse_u64()?;
let mut fields = Vec::new();
self.skip_trivia();
while self.peek_one() != Some(close) {
fields.push(self.parse_tree()?);
self.skip_trivia();
}
self.advance_one();
if variant_count == 0 {
Err("variant count cannot be zero".to_owned())?;
}
if variant_count > (MAX_ADT_VARIANTS as u64) {
Err("adt has too many variants".to_owned())?;
}
if variant_index >= variant_count {
Err("variant index out of range".to_owned())?;
}
let variant_index = variant_index as usize;
let variant_count = variant_count as usize;
if fields.len() > MAX_ADT_FIELDS {
Err("adt has too many fields".to_owned())?;
}
Ok(Tree::Adt { lab, variant_index, variant_count, fields })
} else {
let mut ports = Vec::new();
self.skip_trivia();
while self.peek_one() != Some(close) {
ports.push(self.parse_tree()?);
self.skip_trivia();
}
self.advance_one();
if ports.len() > MAX_ARITY {
Err("ctr has too many ports".to_owned())?;
}
Ok(Tree::Ctr { lab, ports })
}
}
Some('@') => {
self.advance_one();
self.skip_trivia();
let nam = self.parse_name()?;
Ok(Tree::Ref { nam })
}
Some('#') => {
self.advance_one();
let is_neg = self.consume("-").is_ok();
let num = self.take_while(|c| c.is_alphanumeric() || c == '.');
if num.contains('.') || num.contains("NaN") || num.contains("inf") {
let mut val: f32 = num.parse().map_err(|err| format!("{err:?}"))?;
if is_neg {
val = -val;
}
Ok(Tree::F32 { val: val.into() })
} else {
let mut val: i64 = parse_int(num)? as i64;
if is_neg {
val = -val;
}
Ok(Tree::Int { val })
}
}
Some('<') => {
self.advance_one();
let op = self.parse_op()?;
let rhs = Box::new(self.parse_tree()?);
let out = Box::new(self.parse_tree()?);
self.consume(">")?;
Ok(Tree::Op { op, rhs, out })
}
Some('?') => {
self.advance_one();
self.consume("<")?;
let zero = self.parse_tree()?;
let succ = self.parse_tree()?;
self.skip_trivia();
if self.peek_one() == Some('>') {
self.advance_one();
Tree::legacy_mat(zero, succ).ok_or_else(|| "invalid legacy match".to_owned())
} else {
let zero = Box::new(zero);
let succ = Box::new(succ);
let out = Box::new(self.parse_tree()?);
self.consume(">")?;
Ok(Tree::Mat { zero, succ, out })
}
}
_ => Ok(Tree::Var { nam: self.parse_name()? }),
}
})
}
fn parse_name(&mut self) -> Result<String, String> {
let name = self.take_while(|c| c.is_alphanumeric() || c == '_' || c == '.' || c == '$');
if name.is_empty() {
return self.expected("name");
}
Ok(name.to_owned())
}
fn parse_op(&mut self) -> Result<Op, String> {
let op = self.take_while(|c| c.is_alphanumeric() || ".+-=*/%<>|&^!?$".contains(c));
op.parse().map_err(|_| format!("Unknown operator: {op:?}"))
}
}
fn parse_int(input: &str) -> Result<u64, String> {
if let Some(rest) = input.strip_prefix("0x") {
u64::from_str_radix(rest, 16).map_err(|err| format!("{err:?}"))
} else if let Some(rest) = input.strip_prefix("0b") {
u64::from_str_radix(rest, 2).map_err(|err| format!("{err:?}"))
} else {
input.parse::<u64>().map_err(|err| format!("{err:?}"))
}
}
fn parse_eof<'i, T>(input: &'i str, parse_fn: impl Fn(&mut HvmcParser<'i>) -> Result<T, String>) -> Result<T, String> {
let mut parser = HvmcParser::new(input);
let out = parse_fn(&mut parser)?;
if parser.index != parser.input.len() {
return Err("Unable to parse the whole input. Is this not an hvmc file?".to_owned());
}
Ok(out)
}
impl FromStr for Book {
type Err = String;
fn from_str(str: &str) -> Result<Self, Self::Err> {
parse_eof(str, HvmcParser::parse_book)
}
}
impl FromStr for Net {
type Err = String;
fn from_str(str: &str) -> Result<Self, Self::Err> {
parse_eof(str, HvmcParser::parse_net)
}
}
impl FromStr for Tree {
type Err = String;
fn from_str(str: &str) -> Result<Self, Self::Err> {
parse_eof(str, HvmcParser::parse_tree)
}
}
impl fmt::Display for Book {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, (name, net)) in self.iter().enumerate() {
if i != 0 {
f.write_str("\n\n")?;
}
write!(f, "@{name} = {net}")?;
}
Ok(())
}
}
impl fmt::Display for Net {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.root)?;
for (a, b) in &self.redexes {
write!(f, "\n & {a} ~ {b}")?;
}
Ok(())
}
}
impl fmt::Display for Tree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
maybe_grow(move || match self {
Tree::Era => write!(f, "*"),
Tree::Ctr { lab, ports } => {
match lab {
0 => write!(f, "("),
1 => write!(f, "["),
_ => write!(f, "{{{lab}"),
}?;
let mut space = *lab > 1;
for port in ports {
if space {
write!(f, " ")?;
}
write!(f, "{port}")?;
space = true;
}
match lab {
0 => write!(f, ")"),
1 => write!(f, "]"),
_ => write!(f, "}}"),
}?;
Ok(())
}
Tree::Adt { lab, variant_index, variant_count, fields } => {
match lab {
0 => write!(f, "("),
1 => write!(f, "["),
_ => write!(f, "{{{lab}"),
}?;
write!(f, ":{}:{}", variant_index, variant_count)?;
for field in fields {
write!(f, " {field}")?;
}
match lab {
0 => write!(f, ")"),
1 => write!(f, "]"),
_ => write!(f, "}}"),
}?;
Ok(())
}
Tree::Var { nam } => write!(f, "{nam}"),
Tree::Ref { nam } => write!(f, "@{nam}"),
Tree::Int { val } => write!(f, "#{val}"),
Tree::F32 { val } => write!(f, "#{:?}", val.0),
Tree::Op { op, rhs, out } => write!(f, "<{op} {rhs} {out}>"),
Tree::Mat { zero, succ, out } => write!(f, "?<{zero} {succ} {out}>"),
})
}
}
impl Clone for Tree {
fn clone(&self) -> Tree {
maybe_grow(|| match self {
Tree::Era => Tree::Era,
Tree::Int { val } => Tree::Int { val: *val },
Tree::F32 { val } => Tree::F32 { val: *val },
Tree::Ref { nam } => Tree::Ref { nam: nam.clone() },
Tree::Ctr { lab, ports } => Tree::Ctr { lab: *lab, ports: ports.clone() },
Tree::Op { op, rhs, out } => Tree::Op { op: *op, rhs: rhs.clone(), out: out.clone() },
Tree::Mat { zero, succ, out } => Tree::Mat { zero: zero.clone(), succ: succ.clone(), out: out.clone() },
Tree::Adt { lab, variant_index, variant_count, fields } => {
Tree::Adt { lab: *lab, variant_index: *variant_index, variant_count: *variant_count, fields: fields.clone() }
}
Tree::Var { nam } => Tree::Var { nam: nam.clone() },
})
}
}
impl Drop for Tree {
fn drop(&mut self) {
loop {
let mut i = self.children_mut().filter(|x| x.children().len() != 0);
let Some(x) = i.next() else { break };
if { i }.next().is_none() {
*self = mem::take(x);
continue;
}
let d = mem::take(x.children_mut().next_back().unwrap());
let b = mem::replace(x, d);
let a = mem::replace(self, b);
mem::forget(mem::replace(self.children_mut().next_back().unwrap(), a));
}
}
}
#[test]
fn test_tree_drop() {
use alloc::vec;
drop(Tree::from_str("((* (* *)) (* *))"));
let mut long_tree = Tree::Era;
let mut cursor = &mut long_tree;
for _ in 0 .. 100_000 {
*cursor = Tree::Ctr { lab: 0, ports: vec![Tree::Era, Tree::Era] };
let Tree::Ctr { ports, .. } = cursor else { unreachable!() };
cursor = &mut ports[0];
}
drop(long_tree);
let mut big_tree = Tree::Era;
for _ in 0 .. 16 {
big_tree = Tree::Ctr { lab: 0, ports: vec![big_tree.clone(), big_tree] };
}
drop(big_tree);
}