#![allow(clippy::unwrap_used, dead_code)]
use ast_lang::{Arena, Id, Node, Span};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Lit(i64, Span),
Neg(Id<Expr>, Span),
Add(Id<Expr>, Id<Expr>, Span),
}
impl Node for Expr {
fn span(&self) -> Span {
match self {
Expr::Lit(_, s) | Expr::Neg(_, s) | Expr::Add(_, _, s) => *s,
}
}
fn each_child(&self, f: &mut dyn FnMut(Id<Self>)) {
match self {
Expr::Lit(..) => {}
Expr::Neg(a, _) => f(*a),
Expr::Add(a, b, _) => {
f(*a);
f(*b);
}
}
}
fn map_children(&self, f: &mut dyn FnMut(Id<Self>) -> Id<Self>) -> Self {
match self {
Expr::Lit(v, s) => Expr::Lit(*v, *s),
Expr::Neg(a, s) => Expr::Neg(f(*a), *s),
Expr::Add(a, b, s) => Expr::Add(f(*a), f(*b), *s),
}
}
}
#[derive(Clone, Debug)]
pub enum Shape {
Lit,
Neg(Box<Shape>),
Add(Box<Shape>, Box<Shape>),
}
impl Shape {
pub fn count(&self) -> usize {
match self {
Shape::Lit => 1,
Shape::Neg(a) => 1 + a.count(),
Shape::Add(a, b) => 1 + a.count() + b.count(),
}
}
}
pub fn build(shape: &Shape, arena: &mut Arena<Expr>) -> Id<Expr> {
match shape {
Shape::Lit => {
let at = arena.len() as u32;
arena.alloc(Expr::Lit(at as i64, Span::new(at, at + 1)))
}
Shape::Neg(a) => {
let child = build(a, arena);
let at = arena.len() as u32;
arena.alloc(Expr::Neg(child, Span::new(at, at + 1)))
}
Shape::Add(a, b) => {
let left = build(a, arena);
let right = build(b, arena);
let at = arena.len() as u32;
arena.alloc(Expr::Add(left, right, Span::new(at, at + 1)))
}
}
}
pub fn deep_chain(depth: usize) -> (Arena<Expr>, Id<Expr>) {
let mut arena = Arena::new();
let mut id = arena.alloc(Expr::Lit(0, Span::new(0, 1)));
for _ in 0..depth {
let at = arena.len() as u32;
id = arena.alloc(Expr::Neg(id, Span::new(at, at + 1)));
}
(arena, id)
}