use std::fmt::{self, Display, Formatter};
use crate::span::{SourceSpan, Spanned};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Function<'src>
{
pub parameters: Option<Vec<Parameter<'src>>>,
pub body: Expression<'src>,
pub span: SourceSpan
}
impl Display for Function<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
if let Some(ref parameters) = self.parameters
{
for (i, param) in parameters.iter().enumerate()
{
if i > 0
{
write!(f, ", ")?;
}
write!(f, "{}", param)?;
}
write!(f, ": ")?;
}
write!(f, "{}", self.body)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Parameter<'src>
{
pub name: &'src str,
pub span: SourceSpan
}
impl Display for Parameter<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.name)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group<'src>
{
pub expression: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Group<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "({})", self.expression)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Constant
{
pub value: i32,
pub span: SourceSpan
}
impl Display for Constant
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.value)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Variable<'src>
{
pub name: &'src str,
pub span: SourceSpan
}
impl Display for Variable<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{{{}}}", self.name)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Binding<'src>
{
pub name: &'src str,
pub name_span: SourceSpan,
pub expression: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Binding<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{}@({})", self.name, self.expression)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Range<'src>
{
pub start: Box<Expression<'src>>,
pub end: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Range<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "[{}:{}]", self.start, self.end)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expression<'src>
{
Group(Group<'src>),
Constant(Constant),
Variable(Variable<'src>),
Binding(Binding<'src>),
Range(Range<'src>),
Dice(DiceExpression<'src>),
Arithmetic(ArithmeticExpression<'src>)
}
impl<'src> Expression<'src>
{
pub fn accept<V: ASTVisitor<'src>>(
&'src self,
visitor: &mut V
) -> Result<V::Output, V::Error>
{
match self
{
Expression::Group(g) => visitor.visit_group(g),
Expression::Constant(c) => visitor.visit_constant(c),
Expression::Variable(v) => visitor.visit_variable(v),
Expression::Binding(b) => visitor.visit_binding(b),
Expression::Range(r) => visitor.visit_range(r),
Expression::Dice(d) => d.accept(visitor),
Expression::Arithmetic(a) => a.accept(visitor)
}
}
}
impl Display for Expression<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
match self
{
Expression::Group(group) => write!(f, "{}", group),
Expression::Constant(constant) => write!(f, "{}", constant),
Expression::Variable(variable) => write!(f, "{}", variable),
Expression::Binding(binding) => write!(f, "{}", binding),
Expression::Range(range) => write!(f, "{}", range),
Expression::Dice(dice) => write!(f, "{}", dice),
Expression::Arithmetic(arithmetic) => write!(f, "{}", arithmetic)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StandardDice<'src>
{
pub count: Box<Expression<'src>>,
pub faces: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for StandardDice<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{}D{}", self.count, self.faces)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CustomDice<'src>
{
pub count: Box<Expression<'src>>,
pub faces: Vec<i32>,
pub span: SourceSpan
}
impl Display for CustomDice<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{}D[", self.count)?;
for (i, face) in self.faces.iter().enumerate()
{
if i > 0
{
write!(f, ", ")?;
}
write!(f, "{}", face)?;
}
write!(f, "]")
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DropLowest<'src>
{
pub dice: Box<DiceExpression<'src>>,
pub drop: Option<Box<Expression<'src>>>,
pub span: SourceSpan
}
impl Display for DropLowest<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} drop lowest", self.dice)?;
if let Some(ref drop) = self.drop
{
write!(f, " {}", drop)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DropHighest<'src>
{
pub dice: Box<DiceExpression<'src>>,
pub drop: Option<Box<Expression<'src>>>,
pub span: SourceSpan
}
impl Display for DropHighest<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} drop highest", self.dice)?;
if let Some(ref drop) = self.drop
{
write!(f, " {}", drop)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DiceExpression<'src>
{
Standard(StandardDice<'src>),
Custom(CustomDice<'src>),
DropLowest(DropLowest<'src>),
DropHighest(DropHighest<'src>)
}
impl<'src> DiceExpression<'src>
{
pub fn accept<V: ASTVisitor<'src>>(
&'src self,
visitor: &mut V
) -> Result<V::Output, V::Error>
{
match self
{
DiceExpression::Standard(d) => visitor.visit_standard_dice(d),
DiceExpression::Custom(d) => visitor.visit_custom_dice(d),
DiceExpression::DropLowest(d) => visitor.visit_drop_lowest(d),
DiceExpression::DropHighest(d) => visitor.visit_drop_highest(d)
}
}
}
impl Display for DiceExpression<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
match self
{
DiceExpression::Standard(dice) => write!(f, "{}", dice),
DiceExpression::Custom(dice) => write!(f, "{}", dice),
DiceExpression::DropLowest(drop) => write!(f, "{}", drop),
DiceExpression::DropHighest(drop) => write!(f, "{}", drop)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Add<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Add<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} + {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Sub<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Sub<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} - {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Mul<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Mul<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} * {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Div<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Div<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} / {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Mod<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Mod<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} % {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Exp<'src>
{
pub left: Box<Expression<'src>>,
pub right: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Exp<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "{} ^ {}", self.left, self.right)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Neg<'src>
{
pub operand: Box<Expression<'src>>,
pub span: SourceSpan
}
impl Display for Neg<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
write!(f, "-{}", self.operand)
}
}
pub trait ASTVisitor<'src>
{
type Output;
type Error;
fn visit_function(
&mut self,
node: &'src Function<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_group(
&mut self,
node: &'src Group<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_constant(
&mut self,
node: &Constant
) -> Result<Self::Output, Self::Error>;
fn visit_variable(
&mut self,
node: &'src Variable<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_binding(
&mut self,
node: &'src Binding<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_range(
&mut self,
node: &'src Range<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_standard_dice(
&mut self,
node: &'src StandardDice<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_custom_dice(
&mut self,
node: &'src CustomDice<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_drop_lowest(
&mut self,
node: &'src DropLowest<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_drop_highest(
&mut self,
node: &'src DropHighest<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_add(
&mut self,
node: &'src Add<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_sub(
&mut self,
node: &'src Sub<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_mul(
&mut self,
node: &'src Mul<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_div(
&mut self,
node: &'src Div<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_mod(
&mut self,
node: &'src Mod<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_exp(
&mut self,
node: &'src Exp<'src>
) -> Result<Self::Output, Self::Error>;
fn visit_neg(
&mut self,
node: &'src Neg<'src>
) -> Result<Self::Output, Self::Error>;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ArithmeticExpression<'src>
{
Add(Add<'src>),
Sub(Sub<'src>),
Mul(Mul<'src>),
Div(Div<'src>),
Mod(Mod<'src>),
Exp(Exp<'src>),
Neg(Neg<'src>)
}
impl<'src> ArithmeticExpression<'src>
{
pub fn accept<V: ASTVisitor<'src>>(
&'src self,
visitor: &mut V
) -> Result<V::Output, V::Error>
{
match self
{
ArithmeticExpression::Add(a) => visitor.visit_add(a),
ArithmeticExpression::Sub(s) => visitor.visit_sub(s),
ArithmeticExpression::Mul(m) => visitor.visit_mul(m),
ArithmeticExpression::Div(d) => visitor.visit_div(d),
ArithmeticExpression::Mod(m) => visitor.visit_mod(m),
ArithmeticExpression::Exp(e) => visitor.visit_exp(e),
ArithmeticExpression::Neg(n) => visitor.visit_neg(n)
}
}
}
impl Display for ArithmeticExpression<'_>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
{
match self
{
ArithmeticExpression::Add(add) => write!(f, "{}", add),
ArithmeticExpression::Sub(sub) => write!(f, "{}", sub),
ArithmeticExpression::Mul(mul) => write!(f, "{}", mul),
ArithmeticExpression::Div(div) => write!(f, "{}", div),
ArithmeticExpression::Mod(r#mod) => write!(f, "{}", r#mod),
ArithmeticExpression::Exp(exp) => write!(f, "{}", exp),
ArithmeticExpression::Neg(neg) => write!(f, "{}", neg)
}
}
}
impl Spanned for Function<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Function {
parameters: self
.parameters
.as_ref()
.map(|ps| ps.iter().map(Spanned::untethered).collect()),
body: self.body.untethered(),
span: SourceSpan::default()
}
}
}
impl Spanned for Parameter<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Parameter {
name: self.name,
span: SourceSpan::default()
}
}
}
impl Spanned for Group<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Group {
expression: Box::new(self.expression.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Constant
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Constant {
value: self.value,
span: SourceSpan::default()
}
}
}
impl Spanned for Variable<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Variable {
name: self.name,
span: SourceSpan::default()
}
}
}
impl Spanned for Binding<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Binding {
name: self.name,
name_span: SourceSpan::default(),
expression: Box::new(self.expression.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Range<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Range {
start: Box::new(self.start.untethered()),
end: Box::new(self.end.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Expression<'_>
{
fn span(&self) -> SourceSpan
{
match self
{
Expression::Group(g) => g.span(),
Expression::Constant(c) => c.span(),
Expression::Variable(v) => v.span(),
Expression::Binding(b) => b.span(),
Expression::Range(r) => r.span(),
Expression::Dice(d) => d.span(),
Expression::Arithmetic(a) => a.span()
}
}
fn untethered(&self) -> Self
{
match self
{
Expression::Group(g) => Expression::Group(g.untethered()),
Expression::Constant(c) => Expression::Constant(c.untethered()),
Expression::Variable(v) => Expression::Variable(v.untethered()),
Expression::Binding(b) => Expression::Binding(b.untethered()),
Expression::Range(r) => Expression::Range(r.untethered()),
Expression::Dice(d) => Expression::Dice(d.untethered()),
Expression::Arithmetic(a) => Expression::Arithmetic(a.untethered())
}
}
}
impl Spanned for StandardDice<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
StandardDice {
count: Box::new(self.count.untethered()),
faces: Box::new(self.faces.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for CustomDice<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
CustomDice {
count: Box::new(self.count.untethered()),
faces: self.faces.clone(),
span: SourceSpan::default()
}
}
}
impl Spanned for DropLowest<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
DropLowest {
dice: Box::new(self.dice.untethered()),
drop: self.drop.as_ref().map(|d| Box::new(d.untethered())),
span: SourceSpan::default()
}
}
}
impl Spanned for DropHighest<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
DropHighest {
dice: Box::new(self.dice.untethered()),
drop: self.drop.as_ref().map(|d| Box::new(d.untethered())),
span: SourceSpan::default()
}
}
}
impl Spanned for DiceExpression<'_>
{
fn span(&self) -> SourceSpan
{
match self
{
DiceExpression::Standard(d) => d.span(),
DiceExpression::Custom(d) => d.span(),
DiceExpression::DropLowest(d) => d.span(),
DiceExpression::DropHighest(d) => d.span()
}
}
fn untethered(&self) -> Self
{
match self
{
DiceExpression::Standard(d) =>
{
DiceExpression::Standard(d.untethered())
},
DiceExpression::Custom(d) => DiceExpression::Custom(d.untethered()),
DiceExpression::DropLowest(d) =>
{
DiceExpression::DropLowest(d.untethered())
},
DiceExpression::DropHighest(d) =>
{
DiceExpression::DropHighest(d.untethered())
},
}
}
}
impl Spanned for Add<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Add {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Sub<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Sub {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Mul<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Mul {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Div<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Div {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Mod<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Mod {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Exp<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Exp {
left: Box::new(self.left.untethered()),
right: Box::new(self.right.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for Neg<'_>
{
fn span(&self) -> SourceSpan { self.span }
fn untethered(&self) -> Self
{
Neg {
operand: Box::new(self.operand.untethered()),
span: SourceSpan::default()
}
}
}
impl Spanned for ArithmeticExpression<'_>
{
fn span(&self) -> SourceSpan
{
match self
{
ArithmeticExpression::Add(a) => a.span(),
ArithmeticExpression::Sub(s) => s.span(),
ArithmeticExpression::Mul(m) => m.span(),
ArithmeticExpression::Div(d) => d.span(),
ArithmeticExpression::Mod(m) => m.span(),
ArithmeticExpression::Exp(e) => e.span(),
ArithmeticExpression::Neg(n) => n.span()
}
}
fn untethered(&self) -> Self
{
match self
{
ArithmeticExpression::Add(a) =>
{
ArithmeticExpression::Add(a.untethered())
},
ArithmeticExpression::Sub(s) =>
{
ArithmeticExpression::Sub(s.untethered())
},
ArithmeticExpression::Mul(m) =>
{
ArithmeticExpression::Mul(m.untethered())
},
ArithmeticExpression::Div(d) =>
{
ArithmeticExpression::Div(d.untethered())
},
ArithmeticExpression::Mod(m) =>
{
ArithmeticExpression::Mod(m.untethered())
},
ArithmeticExpression::Exp(e) =>
{
ArithmeticExpression::Exp(e.untethered())
},
ArithmeticExpression::Neg(n) =>
{
ArithmeticExpression::Neg(n.untethered())
},
}
}
}