use peepmatic_macro::Ast;
use peepmatic_runtime::{
r#type::{BitWidth, Type},
unquote::UnquoteOperator,
};
use std::cell::Cell;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use wast::Id;
#[derive(Debug, Clone, Copy)]
pub enum DynAstRef<'a, TOperator> {
Optimizations(&'a Optimizations<'a, TOperator>),
Optimization(&'a Optimization<'a, TOperator>),
Lhs(&'a Lhs<'a, TOperator>),
Rhs(&'a Rhs<'a, TOperator>),
Pattern(&'a Pattern<'a, TOperator>),
Precondition(&'a Precondition<'a, TOperator>),
ConstraintOperand(&'a ConstraintOperand<'a, TOperator>),
ValueLiteral(&'a ValueLiteral<'a, TOperator>),
Constant(&'a Constant<'a, TOperator>),
PatternOperation(&'a Operation<'a, TOperator, Pattern<'a, TOperator>>),
Variable(&'a Variable<'a, TOperator>),
Integer(&'a Integer<'a, TOperator>),
Boolean(&'a Boolean<'a, TOperator>),
ConditionCode(&'a ConditionCode<'a, TOperator>),
Unquote(&'a Unquote<'a, TOperator>),
RhsOperation(&'a Operation<'a, TOperator, Rhs<'a, TOperator>>),
}
impl<'a, 'b, TOperator> ChildNodes<'a, 'b, TOperator> for DynAstRef<'a, TOperator> {
fn child_nodes(&'b self, sink: &mut impl Extend<DynAstRef<'a, TOperator>>) {
match self {
Self::Optimizations(x) => x.child_nodes(sink),
Self::Optimization(x) => x.child_nodes(sink),
Self::Lhs(x) => x.child_nodes(sink),
Self::Rhs(x) => x.child_nodes(sink),
Self::Pattern(x) => x.child_nodes(sink),
Self::Precondition(x) => x.child_nodes(sink),
Self::ConstraintOperand(x) => x.child_nodes(sink),
Self::ValueLiteral(x) => x.child_nodes(sink),
Self::Constant(x) => x.child_nodes(sink),
Self::PatternOperation(x) => x.child_nodes(sink),
Self::Variable(x) => x.child_nodes(sink),
Self::Integer(x) => x.child_nodes(sink),
Self::Boolean(x) => x.child_nodes(sink),
Self::ConditionCode(x) => x.child_nodes(sink),
Self::Unquote(x) => x.child_nodes(sink),
Self::RhsOperation(x) => x.child_nodes(sink),
}
}
}
pub trait Ast<'a, TOperator>: 'a + ChildNodes<'a, 'a, TOperator> + Span
where
DynAstRef<'a, TOperator>: From<&'a Self>,
TOperator: 'a,
{
}
impl<'a, T, TOperator> Ast<'a, TOperator> for T
where
T: 'a + ?Sized + ChildNodes<'a, 'a, TOperator> + Span,
DynAstRef<'a, TOperator>: From<&'a Self>,
TOperator: 'a,
{
}
pub trait ChildNodes<'a, 'b, TOperator>
where
TOperator: 'a,
{
fn child_nodes(&'b self, sink: &mut impl Extend<DynAstRef<'a, TOperator>>);
}
pub trait Span {
fn span(&self) -> wast::Span;
}
#[derive(Debug, Ast)]
pub struct Optimizations<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(flatten)]
pub optimizations: Vec<Optimization<'a, TOperator>>,
}
#[derive(Debug, Ast)]
pub struct Optimization<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
pub lhs: Lhs<'a, TOperator>,
pub rhs: Rhs<'a, TOperator>,
}
#[derive(Debug, Ast)]
pub struct Lhs<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
pub pattern: Pattern<'a, TOperator>,
#[peepmatic(flatten)]
pub preconditions: Vec<Precondition<'a, TOperator>>,
}
#[derive(Debug, Ast)]
pub enum Pattern<'a, TOperator> {
ValueLiteral(ValueLiteral<'a, TOperator>),
Constant(Constant<'a, TOperator>),
Operation(Operation<'a, TOperator, Pattern<'a, TOperator>>),
Variable(Variable<'a, TOperator>),
}
#[derive(Debug, Ast)]
pub enum ValueLiteral<'a, TOperator> {
Integer(Integer<'a, TOperator>),
Boolean(Boolean<'a, TOperator>),
ConditionCode(ConditionCode<'a, TOperator>),
}
#[derive(Debug, PartialEq, Eq, Ast)]
pub struct Integer<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub value: i64,
#[peepmatic(skip_child)]
pub bit_width: Cell<Option<BitWidth>>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
impl<TOperator> Hash for Integer<'_, TOperator> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let Integer {
span,
value,
bit_width,
marker: _,
} = self;
span.hash(state);
value.hash(state);
let bit_width = bit_width.get();
bit_width.hash(state);
}
}
#[derive(Debug, PartialEq, Eq, Ast)]
pub struct Boolean<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub value: bool,
#[peepmatic(skip_child)]
pub bit_width: Cell<Option<BitWidth>>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
impl<TOperator> Hash for Boolean<'_, TOperator> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let Boolean {
span,
value,
bit_width,
marker: _,
} = self;
span.hash(state);
value.hash(state);
let bit_width = bit_width.get();
bit_width.hash(state);
}
}
#[derive(Debug, Ast)]
pub struct ConditionCode<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub cc: peepmatic_runtime::cc::ConditionCode,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
#[derive(Debug, Ast)]
pub struct Constant<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub id: Id<'a>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
#[derive(Debug, Ast)]
pub struct Variable<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub id: Id<'a>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
#[derive(Debug, Ast)]
#[peepmatic(no_into_dyn_node)]
pub struct Operation<'a, TOperator, TOperand>
where
TOperator: 'a,
TOperand: 'a + Ast<'a, TOperator>,
DynAstRef<'a, TOperator>: From<&'a TOperand>,
{
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub operator: TOperator,
#[peepmatic(skip_child)]
pub r#type: Cell<Option<Type>>,
#[peepmatic(flatten)]
pub operands: Vec<TOperand>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a ()>,
}
impl<'a, TOperator> From<&'a Operation<'a, TOperator, Pattern<'a, TOperator>>>
for DynAstRef<'a, TOperator>
{
#[inline]
fn from(o: &'a Operation<'a, TOperator, Pattern<'a, TOperator>>) -> DynAstRef<'a, TOperator> {
DynAstRef::PatternOperation(o)
}
}
impl<'a, TOperator> From<&'a Operation<'a, TOperator, Rhs<'a, TOperator>>>
for DynAstRef<'a, TOperator>
{
#[inline]
fn from(o: &'a Operation<'a, TOperator, Rhs<'a, TOperator>>) -> DynAstRef<'a, TOperator> {
DynAstRef::RhsOperation(o)
}
}
#[derive(Debug, Ast)]
pub struct Precondition<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub constraint: Constraint,
#[peepmatic(flatten)]
pub operands: Vec<ConstraintOperand<'a, TOperator>>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Constraint {
IsPowerOfTwo,
BitWidth,
FitsInNativeWord,
}
#[derive(Debug, Ast)]
pub enum ConstraintOperand<'a, TOperator> {
ValueLiteral(ValueLiteral<'a, TOperator>),
Constant(Constant<'a, TOperator>),
Variable(Variable<'a, TOperator>),
}
#[derive(Debug, Ast)]
pub enum Rhs<'a, TOperator> {
ValueLiteral(ValueLiteral<'a, TOperator>),
Constant(Constant<'a, TOperator>),
Variable(Variable<'a, TOperator>),
Unquote(Unquote<'a, TOperator>),
Operation(Operation<'a, TOperator, Rhs<'a, TOperator>>),
}
#[derive(Debug, Ast)]
pub struct Unquote<'a, TOperator> {
#[peepmatic(skip_child)]
pub span: wast::Span,
#[peepmatic(skip_child)]
pub operator: UnquoteOperator,
#[peepmatic(flatten)]
pub operands: Vec<Rhs<'a, TOperator>>,
#[allow(missing_docs)]
#[peepmatic(skip_child)]
pub marker: PhantomData<&'a TOperator>,
}