walpurgis/src/ast/expr.rs
Akemi Izuko 16a9632f9d
All checks were successful
ci/woodpecker/push/build_rust Pipeline was successful
Ast: traits for basetype
2023-11-17 14:36:34 -07:00

238 lines
6.2 KiB
Rust

use std::string::ToString;
use super::BaseType;
use super::Quantifier;
use super::GazType;
/// Thin wrapper around all expression types, to avoid trait objects
#[derive(Clone)]
pub enum Expr {
Literal(Box<Literal>),
Variable(Box<Variable>),
BinaryOperator(Box<BinaryOperator>),
}
impl Expr {
pub fn new_literal(x: Literal) -> Self {
Self::Literal(Box::new(x))
}
pub fn new_variable(x: Variable) -> Self {
Self::Variable(Box::new(x))
}
pub fn new_binary_op(x: BinaryOperator) -> Self {
Self::BinaryOperator(Box::new(x))
}
}
impl GazType for Expr {
fn get_base(&self) -> BaseType {
match self {
Expr::Literal(x) => x.get_base(),
Expr::Variable(x) => x.get_base(),
Expr::BinaryOperator(x) => x.get_base(),
}
}
}
impl ToString for Expr {
fn to_string(&self) -> String {
match self {
Expr::Literal(x) => x.to_string(),
Expr::Variable(x) => x.to_string(),
Expr::BinaryOperator(x) => x.to_string(),
}
}
}
#[derive(Debug, Clone)]
pub enum Literal {
Int(i32),
Real(f32),
}
impl ToString for Literal {
fn to_string(&self) -> String {
match *self {
Literal::Int(x) => x.to_string(),
Literal::Real(x) => x.to_string(),
}
}
}
impl GazType for Literal {
fn get_base(&self) -> BaseType {
match *self {
Literal::Int(_) => BaseType::Int,
Literal::Real(_) => BaseType::Real,
}
}
}
#[derive(Clone, Default, Builder)]
#[builder(setter(into))]
pub struct Variable {
type_: BaseType,
quantifier: Quantifier,
name: String,
}
impl Variable {
pub fn get_name(&self) -> String {
self.name.clone()
}
pub fn get_quantifier(&self) -> Quantifier {
self.quantifier
}
}
impl ToString for Variable {
fn to_string(&self) -> String {
self.name.clone()
}
}
impl GazType for Variable {
fn get_base(&self) -> BaseType {
self.type_
}
}
#[derive(Clone)]
enum BinaryOp {
Add(Expr, Expr),
Subtract(Expr, Expr),
Multiply(Expr, Expr),
Divide(Expr, Expr),
}
#[derive(Clone)]
pub struct BinaryOperator {
basetype: BaseType,
op: BinaryOp,
}
impl BinaryOperator {
pub fn add(left: Expr, right: Expr) -> Self {
let is_both_same = left.get_base() == right.get_base();
let is_one_real = left.get_base() == BaseType::Real || right.get_base() == BaseType::Real;
let is_one_int = left.get_base() == BaseType::Int || right.get_base() == BaseType::Int;
let basetype = if is_both_same {
left.get_base()
} else if is_one_real && is_one_int {
BaseType::Real
} else {
panic!("Unsupported types being added: {:?} and {:?}",
left.get_base(), right.get_base());
};
BinaryOperator {
basetype,
op: BinaryOp::Add(left, right),
}
}
pub fn sub(left: Expr, right: Expr) -> Self {
let is_both_same = left.get_base() == right.get_base();
let is_one_real = left.get_base() == BaseType::Real || right.get_base() == BaseType::Real;
let is_one_int = left.get_base() == BaseType::Int || right.get_base() == BaseType::Int;
let basetype = if is_both_same {
left.get_base()
} else if is_one_real && is_one_int {
BaseType::Real
} else {
panic!("Unsupported types being subtracted: {:?} and {:?}",
left.get_base(), right.get_base());
};
BinaryOperator {
basetype,
op: BinaryOp::Subtract(left, right),
}
}
pub fn multiply(left: Expr, right: Expr) -> Self {
let is_both_same = left.get_base() == right.get_base();
let is_one_real = left.get_base() == BaseType::Real || right.get_base() == BaseType::Real;
let is_one_int = left.get_base() == BaseType::Int || right.get_base() == BaseType::Int;
let basetype = if is_both_same {
left.get_base()
} else if is_one_real && is_one_int {
BaseType::Real
} else {
panic!("Unsupported types being multiplied: {:?} and {:?}",
left.get_base(), right.get_base());
};
BinaryOperator {
basetype,
op: BinaryOp::Multiply(left, right),
}
}
pub fn divide(left: Expr, right: Expr) -> Self {
let is_both_same = left.get_base() == right.get_base();
let is_one_real = left.get_base() == BaseType::Real || right.get_base() == BaseType::Real;
let is_one_int = left.get_base() == BaseType::Int || right.get_base() == BaseType::Int;
let basetype = if is_both_same {
left.get_base()
} else if is_one_real && is_one_int {
BaseType::Real
} else {
panic!("Unsupported types being divided: {:?} and {:?}",
left.get_base(), right.get_base());
};
BinaryOperator {
basetype,
op: BinaryOp::Divide(left, right),
}
}
}
impl ToString for BinaryOperator {
fn to_string(&self) -> String {
let mut s = String::new();
s.push('(');
match &self.op {
BinaryOp::Add(l, _) => s.push_str(&l.to_string()),
BinaryOp::Subtract(l, _) => s.push_str(&l.to_string()),
BinaryOp::Multiply(l, _) => s.push_str(&l.to_string()),
BinaryOp::Divide(l, _) => s.push_str(&l.to_string()),
}
s.push(')');
s.push(
match &self.op {
BinaryOp::Add(_, _) => '+',
BinaryOp::Subtract(_, _) => '-',
BinaryOp::Multiply(_, _) => '*',
BinaryOp::Divide(_, _) => '/',
}
);
s.push('(');
match &self.op {
BinaryOp::Add(_, r) => s.push_str(&r.to_string()),
BinaryOp::Subtract(_, r) => s.push_str(&r.to_string()),
BinaryOp::Multiply(_, r) => s.push_str(&r.to_string()),
BinaryOp::Divide(_, r) => s.push_str(&r.to_string()),
}
s.push(')');
s
}
}
impl GazType for BinaryOperator {
fn get_base(&self) -> BaseType {
self.basetype
}
}