use std::fmt;
use std::collections::HashMap;
use num::{BigInt, One};
use score::*;
use moore_common::source::Span;
use moore_common::name::Name;
pub use hir::Dir;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ty {
Named(Span, TypeMarkRef),
Null,
Int(IntTy),
UnboundedInt,
Enum(EnumTy),
Access(Box<Ty>),
Array(ArrayTy),
File(Box<Ty>),
Record(RecordTy),
}
impl Ty {
pub fn kind_desc(&self) -> &'static str {
match *self {
Ty::Named(..) => "named type",
Ty::Null => "null type",
Ty::Int(_) | Ty::UnboundedInt => "integer type",
Ty::Enum(_) => "enumeration type",
Ty::Access(_) => "access type",
Ty::Array(_) => "array type",
Ty::File(..) => "file type",
Ty::Record(_) => "record type",
}
}
}
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<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 fmt::Display for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Ty::Named(span, _) => write!(f, "{}", span.extract()),
Ty::Null => write!(f, "null"),
Ty::Int(ref ty) => write!(f, "{}", ty),
Ty::UnboundedInt => write!(f, "{{integer}}"),
Ty::Enum(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),
}
}
}
#[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 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(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(())
}
}
pub struct DisplayList<'a, T> (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> + Clone, I: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.0.clone();
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(())
}
}