All checks were successful
ci/woodpecker/push/build_rust Pipeline was successful
238 lines
6.2 KiB
Rust
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
|
|
}
|
|
}
|