use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use num::{BigInt, One};
use crate::common::name::Name;
use crate::common::source::Span;
pub use crate::hir::Dir;
use crate::score::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ty {
Named(TyName, TypeMarkRef),
Null,
Int(IntTy),
UniversalInt,
UnboundedInt,
Enum(EnumTy),
Physical(PhysicalTy),
Access(Box<Ty>),
Array(ArrayTy),
File(Box<Ty>),
Record(RecordTy),
Subprog(SubprogTy),
}
impl Ty {
pub fn kind_desc(&self) -> &'static str {
match *self {
Ty::Named(..) => "named type",
Ty::Null => "null type",
Ty::Int(_) | Ty::UnboundedInt | Ty::UniversalInt => "integer type",
Ty::Enum(_) => "enumeration type",
Ty::Physical(_) => "physical type",
Ty::Access(_) => "access type",
Ty::Array(_) => "array type",
Ty::File(..) => "file type",
Ty::Record(_) => "record type",
Ty::Subprog(_) => "subprogram type",
}
}
pub fn is_int(&self) -> bool {
match *self {
Ty::Int(..) | Ty::UnboundedInt | Ty::UniversalInt => true,
_ => false,
}
}
pub fn is_real(&self) -> bool {
match *self {
_ => false,
}
}
}
impl From<IntTy> for Ty {
fn from(t: IntTy) -> Ty {
Ty::Int(t)
}
}
impl From<EnumTy> for Ty {
fn from(t: EnumTy) -> Ty {
Ty::Enum(t)
}
}
impl From<PhysicalTy> for Ty {
fn from(t: PhysicalTy) -> Ty {
Ty::Physical(t)
}
}
impl From<ArrayTy> for Ty {
fn from(t: ArrayTy) -> Ty {
Ty::Array(t)
}
}
impl From<RecordTy> for Ty {
fn from(t: RecordTy) -> Ty {
Ty::Record(t)
}
}
impl From<SubprogTy> for Ty {
fn from(t: SubprogTy) -> Ty {
Ty::Subprog(t)
}
}
impl fmt::Display for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Ty::Named(name, _) => write!(f, "{}", name),
Ty::Null => write!(f, "null"),
Ty::Int(ref ty) => write!(f, "{}", ty),
Ty::UniversalInt => write!(f, "{{universal integer}}"),
Ty::UnboundedInt => write!(f, "{{integer}}"),
Ty::Enum(ref ty) => write!(f, "{}", ty),
Ty::Physical(ref ty) => write!(f, "{}", ty),
Ty::Access(ref ty) => write!(f, "access {}", ty),
Ty::Array(ref ty) => write!(f, "{}", ty),
Ty::File(ref ty) => write!(f, "file of {}", ty),
Ty::Record(ref ty) => write!(f, "{}", ty),
Ty::Subprog(ref ty) => write!(f, "{}", ty),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum TyName {
Span(Span),
Name(Name),
}
impl fmt::Display for TyName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TyName::Span(span) => write!(f, "{}", span.extract()),
TyName::Name(name) => write!(f, "{}", name),
}
}
}
impl From<Span> for TyName {
fn from(span: Span) -> TyName {
TyName::Span(span)
}
}
impl From<Name> for TyName {
fn from(name: Name) -> TyName {
TyName::Name(name)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntTy {
pub dir: Dir,
pub left_bound: BigInt,
pub right_bound: BigInt,
}
impl IntTy {
pub fn new(dir: Dir, left_bound: BigInt, right_bound: BigInt) -> IntTy {
IntTy {
dir: dir,
left_bound: left_bound,
right_bound: right_bound,
}
}
pub fn maybe_null(self) -> Ty {
match self.dir {
Dir::To if self.left_bound >= self.right_bound => Ty::Null,
Dir::Downto if self.left_bound <= self.right_bound => Ty::Null,
_ => self.into(),
}
}
pub fn len(&self) -> BigInt {
match self.dir {
Dir::To => &self.left_bound + BigInt::one() - &self.right_bound,
Dir::Downto => &self.right_bound + BigInt::one() - &self.left_bound,
}
}
}
impl fmt::Display for IntTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {}", self.left_bound, self.dir, self.right_bound)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumTy {
pub decl: TypeDeclRef,
}
impl EnumTy {
pub fn new(decl: TypeDeclRef) -> EnumTy {
EnumTy { decl: decl }
}
}
impl fmt::Display for EnumTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "enum")
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PhysicalTy {
pub decl: TypeDeclRef,
pub base: IntTy,
pub units: Vec<PhysicalUnit>,
pub primary: usize,
}
impl PhysicalTy {
pub fn new(
decl: TypeDeclRef,
base: IntTy,
units: Vec<PhysicalUnit>,
primary: usize,
) -> PhysicalTy {
PhysicalTy {
decl: decl,
base: base,
units: units,
primary: primary,
}
}
}
impl fmt::Display for PhysicalTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} units ({})",
self.base,
DisplayList(
RefCell::new(self.units.iter().map(|u| u.name)),
Some(&","),
Some(&", "),
Some(&", ")
),
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PhysicalUnit {
pub name: Name,
pub abs: BigInt,
pub rel: Option<(BigInt, usize)>,
}
impl PhysicalUnit {
pub fn new(name: Name, abs: BigInt, rel: Option<(BigInt, usize)>) -> PhysicalUnit {
PhysicalUnit {
name: name,
abs: abs,
rel: rel,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArrayTy {
pub indices: Vec<ArrayIndex>,
pub element: Box<Ty>,
}
impl ArrayTy {
pub fn new(indices: Vec<ArrayIndex>, element: Box<Ty>) -> ArrayTy {
assert!(indices.len() > 0);
ArrayTy {
indices: indices,
element: element,
}
}
}
impl fmt::Display for ArrayTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"array ({}) of {}",
DisplayList(
RefCell::new(self.indices.iter()),
Some(&","),
Some(&", "),
Some(&", ")
),
self.element
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArrayIndex {
Unbounded(Box<Ty>),
Constrained(Box<Ty>),
}
impl fmt::Display for ArrayIndex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ArrayIndex::Unbounded(ref ty) => write!(f, "{} range <>", ty),
ArrayIndex::Constrained(ref ty) => write!(f, "{}", ty),
}
}
}
impl ArrayIndex {
pub fn ty(&self) -> &Ty {
match *self {
ArrayIndex::Unbounded(ref ty) => ty.as_ref(),
ArrayIndex::Constrained(ref ty) => ty.as_ref(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RecordTy {
pub fields: Vec<(Name, Box<Ty>)>,
pub lookup: HashMap<Name, usize>,
}
impl RecordTy {
pub fn new(fields: Vec<(Name, Box<Ty>)>) -> RecordTy {
let lookup = fields
.iter()
.enumerate()
.map(|(i, &(n, _))| (n, i))
.collect();
RecordTy {
fields: fields,
lookup: lookup,
}
}
}
impl fmt::Display for RecordTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "record")?;
if self.fields.is_empty() {
return Ok(());
}
write!(f, "\n")?;
for &(name, ref field) in &self.fields {
let indented = format!("{}", field).replace('\n', "\n ");
write!(f, " {}: {};\n", name, indented)?;
}
write!(f, "end record")?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SubprogTy {
pub args: Vec<SubprogTyArg>,
pub ret: Option<Box<Ty>>,
}
impl SubprogTy {
pub fn new(args: Vec<SubprogTyArg>, ret: Option<Ty>) -> SubprogTy {
SubprogTy {
args: args,
ret: ret.map(|t| Box::new(t)),
}
}
}
impl fmt::Display for SubprogTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"({})",
DisplayList(
RefCell::new(self.args.iter()),
Some(&","),
Some(&", "),
Some(&", ")
)
)?;
if let Some(ref ret) = self.ret {
write!(f, " return {}", ret)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SubprogTyArg {
pub ty: Ty,
pub name: Option<Name>,
}
impl SubprogTyArg {
pub fn named(ty: Ty, name: Name) -> SubprogTyArg {
SubprogTyArg {
ty: ty,
name: Some(name),
}
}
pub fn positional(ty: Ty) -> SubprogTyArg {
SubprogTyArg { ty: ty, name: None }
}
}
impl fmt::Display for SubprogTyArg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(name) = self.name {
write!(f, "{}: ", name)?;
}
write!(f, "{}", self.ty)
}
}
pub struct DisplayList<'a, T: 'a>(
RefCell<T>,
Option<&'a fmt::Display>,
Option<&'a fmt::Display>,
Option<&'a fmt::Display>,
);
impl<'a, T, I> fmt::Display for DisplayList<'a, T>
where
T: Iterator<Item = I>,
I: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.0.borrow_mut();
match iter.next() {
Some(x) => write!(f, "{}", x)?,
None => return Ok(()),
}
let mut last = match iter.next() {
Some(x) => x,
None => return Ok(()),
};
let mut had_separator = false;
while let Some(x) = iter.next() {
if let Some(sep) = self.1 {
write!(f, "{}", sep)?;
}
write!(f, "{}", last)?;
last = x;
had_separator = true;
}
if !had_separator {
if let Some(sep) = self.2 {
write!(f, "{}", sep)?;
}
} else {
if let Some(con) = self.3 {
write!(f, "{}", con)?;
}
}
write!(f, "{}", last)?;
Ok(())
}
}