// Copyright (c) 2016-2021 Fabian Schuiki //! This module implements constant value calculation for VHDL. pub use crate::hir::Dir; use crate::score::TypeDeclRef; use crate::ty::*; use num::BigInt; use std::fmt; /// A constant value. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Const { Null, Int(ConstInt), Float(ConstFloat), Enum(ConstEnum), IntRange(ConstIntRange), FloatRange(ConstFloatRange), } impl Const { pub fn negate(self) -> Const { match self { Const::Null => panic!("cannot negate null"), Const::Int(c) => Const::Int(c.negate()), Const::Float(c) => Const::Float(c.negate()), Const::Enum(_) => panic!("cannot negate enumeration literal"), Const::IntRange(_) => panic!("cannot negate integer range"), Const::FloatRange(_) => panic!("cannot negate float range"), } } /// Provide a textual description of the kind of constant. pub fn kind_desc(&self) -> &'static str { match *self { Const::Null => "null", Const::Int(_) => "integer", Const::Float(_) => "float", Const::Enum(_) => "enumeration literal", Const::IntRange(_) => "integer range", Const::FloatRange(_) => "float range", } } } impl From for Const { fn from(k: ConstInt) -> Const { Const::Int(k) } } impl From for Const { fn from(k: ConstFloat) -> Const { Const::Float(k) } } impl From for Const { fn from(k: ConstEnum) -> Const { Const::Enum(k) } } impl From for Const { fn from(k: ConstIntRange) -> Const { Const::IntRange(k) } } impl From for Const { fn from(k: ConstFloatRange) -> Const { Const::FloatRange(k) } } /// A constant integer value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstInt { /// The type of the constant. If `None`, the constant is assumed to be an /// unbounded integer which cannot be mapped to LLHD. pub ty: Option, /// The value of the constant. pub value: BigInt, } impl ConstInt { /// Create a new constant integer. pub fn new(ty: Option, value: BigInt) -> ConstInt { ConstInt { ty: ty, value: value, } } pub fn negate(self) -> ConstInt { ConstInt::new(self.ty, -self.value) } } /// A constant float value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstFloat {} impl ConstFloat { pub fn negate(self) -> ConstFloat { ConstFloat {} } } /// A constant enumeration value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstEnum { /// The type declaration which declared the enum. pub decl: TypeDeclRef, /// The index of the literal. pub index: usize, } impl ConstEnum { /// Create a new constant integer. pub fn new(decl: TypeDeclRef, index: usize) -> ConstEnum { ConstEnum { decl: decl, index: index, } } } /// A constant range value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstRange { pub dir: Dir, pub left_bound: T, pub right_bound: T, } impl ConstRange where T: fmt::Display + fmt::Debug, { /// Create a new constant range. pub fn new(dir: Dir, left_bound: T, right_bound: T) -> ConstRange { ConstRange { dir: dir, left_bound: left_bound, right_bound: right_bound, } } } pub type ConstIntRange = ConstRange; pub type ConstFloatRange = ConstRange; // ----- FORMATTING ------------------------------------------------------------ impl fmt::Display for Const { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Const::Null => write!(f, "null"), Const::Int(ref k) => k.fmt(f), Const::Float(ref k) => k.fmt(f), Const::Enum(ref k) => k.fmt(f), Const::IntRange(ref k) => k.fmt(f), Const::FloatRange(ref k) => k.fmt(f), } } } impl fmt::Display for ConstInt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.value.fmt(f) } } impl fmt::Display for ConstEnum { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } } impl fmt::Display for ConstFloat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } } impl fmt::Display for ConstRange where T: fmt::Display + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {} {}", self.left_bound, self.dir, self.right_bound) } }