1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) 2017 Fabian Schuiki

//! Types of values.

pub use self::TypeKind::*;
use std;
use std::sync::Arc;
use crate::util::write_implode;

pub type Type = Arc<TypeKind>;

/// The different kinds of types.
#[derive(Debug, PartialEq, Eq)]
pub enum TypeKind {
    /// The `void` type.
    VoidType,
    /// The `time` type.
    TimeType,
    /// Integer types like `i32`.
    IntType(usize),
    /// Enumerated types like `n42`.
    EnumType(usize),
    /// Pointer types like `i32*`.
    PointerType(Type),
    /// Signal types like `i32$`.
    SignalType(Type),
    /// Vector types like `<4 x i32>`.
    VectorType(usize, Type),
    /// Struct types like `{i8, i32}`.
    StructType(Vec<Type>),
    /// Function types like `(i32) void`.
    FuncType(Vec<Type>, Type),
    /// Entity types like `(i8, i8; i32)`.
    EntityType(Vec<Type>, Vec<Type>),
}

impl std::fmt::Display for TypeKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            VoidType => write!(f, "void"),
            TimeType => write!(f, "time"),
            IntType(l) => write!(f, "i{}", l),
            EnumType(l) => write!(f, "n{}", l),
            PointerType(ref ty) => write!(f, "{}*", ty),
            SignalType(ref ty) => write!(f, "{}$", ty),
            VectorType(l, ref ty) => write!(f, "<{} x {}>", l, ty),
            StructType(ref tys) => {
                write!(f, "{{")?;
                write_implode(f, ", ", tys.iter())?;
                write!(f, "}}")?;
                Ok(())
            }
            FuncType(ref args, ref ret) => {
                write!(f, "(")?;
                write_implode(f, ", ", args.iter())?;
                write!(f, ") {}", ret)?;
                Ok(())
            }
            EntityType(ref ins, ref outs) => {
                write!(f, "(")?;
                write_implode(f, ", ", ins.iter())?;
                write!(f, ";")?;
                write_implode(f, ", ", outs.iter())?;
                write!(f, ")")?;
                Ok(())
            }
        }
    }
}

impl TypeKind {
    /// Unwrap the type into arguments and return type, or panic if the type is
    /// not a function.
    pub fn as_func(&self) -> (&[Type], &Type) {
        match *self {
            FuncType(ref args, ref ret) => (args, ret),
            _ => panic!("as_func called on {}", self),
        }
    }

    /// Unwrap the type into input and output arguments, or panic if the type is
    /// not an entity.
    pub fn as_entity(&self) -> (&[Type], &[Type]) {
        match *self {
            EntityType(ref ins, ref outs) => (ins, outs),
            _ => panic!("as_entity called on {}", self),
        }
    }

    /// Unwrap the type to its integer bit width, or panic if the type is not an
    /// integer.
    pub fn as_int(&self) -> usize {
        match *self {
            IntType(size) => size,
            _ => panic!("as_int called on {}", self),
        }
    }

    /// Unwrap the type to its number of enumerated states, or panic if the type
    /// is not an enum.
    pub fn as_enum(&self) -> usize {
        match *self {
            EnumType(size) => size,
            _ => panic!("as_enum called on {}", self),
        }
    }

    /// Unwrap the type to its signal data type, or panic if the type is not an
    /// integer. E.g. yields the `i8` type in `i8$`.
    pub fn as_signal(&self) -> &Type {
        match *self {
            SignalType(ref ty) => ty,
            _ => panic!("as_signal called on {}", self),
        }
    }

    /// Check if this type is a void type.
    pub fn is_void(&self) -> bool {
        match *self {
            VoidType => true,
            _ => false,
        }
    }
}

/// Create a void type.
pub fn void_ty() -> Type {
    Type::new(VoidType)
}

/// Create a time type.
pub fn time_ty() -> Type {
    Type::new(TimeType)
}

/// Create an integer type of the requested size.
pub fn int_ty(size: usize) -> Type {
    Type::new(IntType(size))
}

/// Create an enum type of the requested size.
pub fn enum_ty(size: usize) -> Type {
    Type::new(EnumType(size))
}

/// Create a pointer type with the requested data type.
pub fn pointer_ty(ty: Type) -> Type {
    Type::new(PointerType(ty))
}

/// Create a signal type with the requested data type.
pub fn signal_ty(ty: Type) -> Type {
    Type::new(SignalType(ty))
}

/// Create a vector type. `size` is the number of elements in the vector, and
/// `ty` the type of each individual element.
pub fn vector_ty(size: usize, ty: Type) -> Type {
    Type::new(VectorType(size, ty))
}

/// Create a struct type. `fields` is an list of types, one for each field.
pub fn struct_ty(fields: Vec<Type>) -> Type {
    Type::new(StructType(fields))
}

/// Create a function type with the given arguments and return type.
pub fn func_ty(args: Vec<Type>, ret: Type) -> Type {
    Type::new(FuncType(args, ret))
}

/// Create an entity type with the given input and output arguments.
pub fn entity_ty(ins: Vec<Type>, outs: Vec<Type>) -> Type {
    Type::new(EntityType(ins, outs))
}