This repository has been archived on 2023-04-04. You can view files and clone it, but cannot push or open issues or pull requests.
p3l/src/ast/expression/mod.rs

434 lines
9.7 KiB
Rust
Raw Normal View History

2022-10-16 20:14:55 +02:00
use super::{Generics, Type};
use proc_macro2::{Ident, Span};
use std::fmt::{self, Debug, Display, Formatter};
use syn::{
punctuated::Punctuated, spanned::Spanned, token::Paren, Index, LitBool, LitInt, Token
};
mod parse;
#[derive(Clone, Copy, Debug)]
pub enum ArithmeticOp {
Add(Token![+]),
Sub(Token![-]),
Mul(Token![*]),
Div(Token![/])
}
impl ArithmeticOp {
pub fn is_add_or_sub_op(self) -> bool {
matches!(self, Self::Add(_) | Self::Sub(_))
}
pub fn is_mul_or_div_op(self) -> bool {
matches!(self, Self::Mul(_) | Self::Div(_))
}
pub fn char(self) -> char {
match self {
ArithmeticOp::Add(_) => '+',
ArithmeticOp::Sub(_) => '-',
ArithmeticOp::Mul(_) => '*',
ArithmeticOp::Div(_) => '/'
}
}
}
impl Spanned for ArithmeticOp {
fn span(&self) -> Span {
match self {
Self::Add(token) => token.span,
Self::Sub(token) => token.span,
Self::Mul(token) => token.span,
Self::Div(token) => token.span
}
}
}
impl Display for ArithmeticOp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.char())
}
}
#[derive(Clone, Copy, Debug)]
pub enum ComparisonOp {
Eq(Token![==]),
Neq(Token![!=]),
Lt(Token![<]),
Le(Token![<=]),
Gt(Token![>]),
Ge(Token![>=])
}
impl ComparisonOp {
fn str(self) -> &'static str {
match self {
ComparisonOp::Eq(_) => "==",
ComparisonOp::Neq(_) => "!=",
ComparisonOp::Lt(_) => "<",
ComparisonOp::Le(_) => "<=",
ComparisonOp::Gt(_) => ">",
ComparisonOp::Ge(_) => ">="
}
}
}
impl Spanned for ComparisonOp {
fn span(&self) -> Span {
match self {
Self::Eq(token) => token.span(),
Self::Neq(token) => token.span(),
Self::Lt(token) => token.span,
Self::Le(token) => token.span(),
Self::Gt(token) => token.span,
Self::Ge(token) => token.span()
}
}
}
impl Display for ComparisonOp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.str())
}
}
#[derive(Clone, Copy, Debug)]
pub enum ConjunctionOp {
And(Token![&&]),
Or(Token![||])
}
impl ConjunctionOp {
fn str(self) -> &'static str {
match self {
ConjunctionOp::And(_) => "&&",
ConjunctionOp::Or(_) => "||"
}
}
}
impl Spanned for ConjunctionOp {
fn span(&self) -> Span {
match self {
Self::And(token) => token.span(),
Self::Or(token) => token.span()
}
}
}
impl Display for ConjunctionOp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.str())
}
}
#[derive(Clone)]
pub enum Expression {
/// An expression enclosed in parentheses.
Term {
paren_token: Paren,
expr: Box<Expression>
},
/// Variable access.
Ident(Ident),
/// A boolean literal.
Bool(LitBool),
/// A number literal.
Literal(LitInt),
/// A boolean negation (`!expr`).
BoolNegation {
not_token: Token![!],
expr: Box<Expression>
},
/// An integer negation (`-expr`).
IntNegation {
minus_token: Token![-],
expr: Box<Expression>
},
/// An arithmetic expression.
Arithmetic {
lhs: Box<Expression>,
op: ArithmeticOp,
rhs: Box<Expression>
},
/// A comparison.
Comparison {
lhs: Box<Expression>,
op: ComparisonOp,
rhs: Box<Expression>
},
/// A conjunction or disjunction.
Conjunction {
lhs: Box<Expression>,
op: ConjunctionOp,
rhs: Box<Expression>
},
/// A tuple constructor.
TupleCtor {
paren_token: Paren,
elems: Punctuated<Expression, Token![,]>
},
/// A tuple index expression.
TupleIndex {
expr: Box<Expression>,
dot_token: Token![.],
index: Index
},
/// An `Rc` constructor.
RcCtor {
span: Span,
paren_token: Paren,
expr: Box<Expression>
},
/// An `Option` constructor.
OptionCtor {
span: Span,
expr: Option<(Paren, Box<Expression>)>
},
/// A deref expression.
Deref {
star_token: Token![*],
expr: Box<Expression>
},
/// A function call.
FnCall {
ident: Ident,
generics: Option<Generics<Type>>,
paren_token: Paren,
inputs: Punctuated<Expression, Token![,]>
}
}
impl Expression {
/// Replace the rightmost part of this expression with the return value
/// of the callback. If self is not a binary expression, or if the filter
/// callback returns false, calls the callback with self.
fn replace_rightmost<F, C>(self, filter: F, callback: C) -> Self
where
F: Fn(&Self) -> bool,
C: FnOnce(Self) -> Self
{
if !filter(&self) {
return callback(self);
}
match self {
Self::Arithmetic { lhs, op, rhs } => Self::Arithmetic {
lhs,
op,
rhs: Box::new(rhs.replace_rightmost(filter, callback))
},
Self::Comparison { lhs, op, rhs } => Self::Comparison {
lhs,
op,
rhs: Box::new(rhs.replace_rightmost(filter, callback))
},
Self::Conjunction { lhs, op, rhs } => Self::Conjunction {
lhs,
op,
rhs: Box::new(rhs.replace_rightmost(filter, callback))
},
this => callback(this)
}
}
}
impl Spanned for Expression {
fn span(&self) -> Span {
match self {
Self::Term { paren_token, .. } => paren_token.span,
Self::Ident(ident) => ident.span(),
Self::Bool(bool) => bool.span(),
Self::Literal(lit) => lit.span(),
Self::BoolNegation { not_token, .. } => not_token.span,
Self::IntNegation { minus_token, .. } => minus_token.span,
Self::Arithmetic { lhs, op, rhs } => lhs
.span()
.join(op.span())
.unwrap()
.join(rhs.span())
.unwrap(),
Self::Comparison { lhs, op, rhs } => lhs
.span()
.join(op.span())
.unwrap()
.join(rhs.span())
.unwrap(),
Self::Conjunction { lhs, op, rhs } => lhs
.span()
.join(op.span())
.unwrap()
.join(rhs.span())
.unwrap(),
Self::TupleCtor { paren_token, .. } => paren_token.span,
Self::TupleIndex {
expr,
dot_token,
index
} => expr
.span()
.join(dot_token.span())
.unwrap()
.join(index.span())
.unwrap(),
Self::RcCtor { span, .. } => *span,
Self::OptionCtor { span, .. } => *span,
Self::Deref { star_token, expr } => {
star_token.span.join(expr.span()).unwrap()
},
Self::FnCall { ident, .. } => ident.span()
}
}
}
impl Debug for Expression {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Term { expr, .. } => f
.debug_struct("Expression::Term")
.field("expr", &expr)
.finish_non_exhaustive(),
Self::Ident(ident) => {
f.debug_tuple("Expression::Ident").field(ident).finish()
},
Self::Bool(lit) => {
f.debug_tuple("Expression::Bool").field(&lit.value).finish()
},
Self::Literal(lit) => f
.debug_tuple("Expression::Literal")
.field(&lit.base10_parse::<isize>())
.finish(),
Self::BoolNegation { expr, .. } => f
.debug_struct("Expression::BoolNegation")
.field("expr", &expr)
.finish_non_exhaustive(),
Self::IntNegation { expr, .. } => f
.debug_struct("Expression::IntNegation")
.field("expr", &expr)
.finish_non_exhaustive(),
Self::Arithmetic { lhs, op, rhs } => f
.debug_struct("Expression::Arithmetic")
.field("lhs", &lhs)
.field("op", &op.char())
.field("rhs", &rhs)
.finish(),
Self::Comparison { lhs, op, rhs } => f
.debug_struct("Expression::Comparison")
.field("lhs", &lhs)
.field("op", &op.str())
.field("rhs", &rhs)
.finish(),
Self::Conjunction { lhs, op, rhs } => f
.debug_struct("Expression::Conjunction")
.field("lhs", &lhs)
.field("op", &op.str())
.field("rhs", &rhs)
.finish(),
Self::TupleCtor { elems, .. } => f
.debug_struct("Expression::TupleCtor")
.field("elems", &elems)
.finish_non_exhaustive(),
Self::TupleIndex { expr, index, .. } => f
.debug_struct("Expression::TupleCtor")
.field("expr", &expr)
.field("index", &index.index)
.finish_non_exhaustive(),
Self::RcCtor { expr, .. } => f
.debug_struct("Expression::RcCtor")
.field("expr", &expr)
.finish_non_exhaustive(),
Self::OptionCtor { expr, .. } => f
.debug_struct("Expression::OptionCtor")
.field("expr", &expr.as_ref().map(|(_, expr)| expr))
.finish_non_exhaustive(),
Self::Deref { expr, .. } => f
.debug_struct("Expression::Deref")
.field("expr", &expr)
.finish_non_exhaustive(),
Self::FnCall { ident, .. } => f
.debug_struct("Expression::FnCall")
.field("ident", &ident)
.finish_non_exhaustive()
}
}
}
impl Display for Expression {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Term { expr, .. } => write!(f, "({{ {expr} }})"),
Self::Ident(ident) => {
write!(f, "{ident}")
},
Self::Bool(lit) => match lit.value() {
true => f.write_str("true"),
false => f.write_str("false")
},
Self::Literal(lit) => f.write_str(lit.base10_digits()),
Self::BoolNegation { expr, .. } => write!(f, "!{{ {expr} }}"),
Self::IntNegation { expr, .. } => write!(f, "-{{ {expr} }}"),
Self::Arithmetic { lhs, op, rhs } => {
write!(f, "{{ {lhs} }} {op} {{ {rhs} }}")
},
Self::Comparison { lhs, op, rhs } => {
write!(f, "{{ {lhs} }} {op} {{ {rhs} }}")
},
Self::Conjunction { lhs, op, rhs } => {
write!(f, "{{ {lhs} }} {op} {{ {rhs} }}")
},
Self::TupleCtor { elems, .. } => {
f.write_str("(")?;
for elem in elems.iter() {
write!(f, "{{ {elem} }}, ")?;
}
f.write_str(")")
},
Self::TupleIndex { expr, index, .. } => {
write!(f, "{{ {expr} }}.{}", index.index)
},
Self::RcCtor { expr, .. } => write!(f, "Rc({{ {expr} }})"),
Self::OptionCtor { expr: None, .. } => write!(f, "None"),
Self::OptionCtor {
expr: Some((_, expr)),
..
} => write!(f, "Some({{ {expr} }})"),
Self::Deref { expr, .. } => write!(f, "*{{ {expr} }}"),
Self::FnCall {
ident,
generics,
inputs,
..
} => {
write!(f, "{ident}")?;
if let Some(g) = generics {
write!(f, "::{g}")?;
}
f.write_str("(")?;
for arg in inputs.iter() {
write!(f, "{{ {arg} }}, ")?;
}
f.write_str(")")
}
}
}
}
#[cfg(test)]
mod tests;