use sindra::inference::{InferTypesBinary, BinaryOpTypes, InferTypesUnary, UnaryOpTypes,
InferPromotion};
use ast::*;
use PType;
lazy_static! {
pub static ref ARITH_RESULT_TABLE: [[Option<PType>; 7]; 7] = [
[None, None, None, None, None, None, None],
[None, Some(PType::Float), Some(PType::Float), None, Some(PType::Complex), None, None],
[None, Some(PType::Float), Some(PType::Int), None, Some(PType::Complex), None, None],
[None, None, None, None, None, None, None],
[None, Some(PType::Complex), Some(PType::Complex), None, Some(PType::Complex), None, None],
[None, None, None, None, None, None, None],
[None, None, None, None, None, None, None],
];
}
lazy_static! {
pub static ref COMPARABLE: [[Option<PType>; 7]; 7] = [
[Some(PType::String), None, None, None, None, None, None],
[None, Some(PType::Float), Some(PType::Float), None, Some(PType::Complex), None, None],
[None, Some(PType::Float), Some(PType::Int), None, Some(PType::Complex), None, None],
[None, None, None, Some(PType::Boolean), None, None, None],
[None, Some(PType::Complex), Some(PType::Complex), None, Some(PType::Complex), None, None],
[None, None, None, None, None, Some(PType::Set), None],
[None, None, None, None, None, None, None],
];
}
impl InferTypesBinary for InfixOp {
type Operand = PType;
fn infer_types(&self, left: PType, right: PType) -> Option<BinaryOpTypes<PType>> {
match *self {
InfixOp::Subtract | InfixOp::Multiply | InfixOp::Divide | InfixOp::Add => {
ARITH_RESULT_TABLE[left as usize][right as usize]
.map(|t| BinaryOpTypes { result: t, left: t, right: t })
},
InfixOp::Power => {
if left == PType::String || right == PType::String {
None
} else {
Some(PType::Float).map(|t| BinaryOpTypes { result: t, left: t, right: t })
}
},
InfixOp::Comparison(_) => {
COMPARABLE[left as usize][right as usize]
.map(|t| BinaryOpTypes { result: PType::Boolean, left: t, right: t })
}
}
}
}
impl InferTypesUnary for PrefixOp {
type Operand = PType;
fn infer_types(&self, operand: PType) -> Option<UnaryOpTypes<PType>> {
match operand {
PType::Float | PType::Int | PType::Complex => Some(operand),
_ => None,
}.map(|t| UnaryOpTypes { result: t, operand: t })
}
}
impl InferTypesUnary for PostfixOp {
type Operand = PType;
fn infer_types(&self, operand: PType) -> Option<UnaryOpTypes<PType>> {
match *self {
PostfixOp::Conjugate => {
match operand {
PType::Float | PType::Int => Some(PType::Float),
PType::Complex => Some(PType::Complex),
_ => None,
}.map(|t| UnaryOpTypes { result: t, operand: t })
},
PostfixOp::Imaginary => {
match operand {
PType::Float | PType::Int => Some(UnaryOpTypes {
result: PType::Complex,
operand: operand
}),
_ => None
}
}
}
}
}
impl InferPromotion for PType {
fn infer_promotion(&self, dest_ty: PType) -> Option<PType> {
match (self, dest_ty) {
(&PType::Int, PType::Float) => {
Some(PType::Float)
},
(&PType::Int, PType::Complex) | (&PType::Float, PType::Complex) => {
Some(PType::Complex)
},
_ => None
}
}
}