futilehdl/src/frontend/types.rs

279 lines
8.2 KiB
Rust
Raw Normal View History

2022-02-15 20:32:55 +00:00
use std::fmt::Debug;
/// Alias for &TypeStruct to reduce repetition
/// and make futura migration to interning
/// easier
2022-02-15 20:32:55 +00:00
pub type Type = InternedType;
2022-02-15 22:56:52 +00:00
#[derive(Copy, Clone, PartialEq)]
2022-02-15 20:32:55 +00:00
pub struct InternedType(usize);
2022-02-15 22:56:52 +00:00
impl Debug for InternedType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Type({})", self.0)
}
}
#[derive(Debug)]
2022-02-15 20:32:55 +00:00
pub struct TypeStruct {
kind: TypeKind,
}
2022-02-06 22:19:55 +00:00
#[derive(Debug)]
2022-02-15 20:32:55 +00:00
enum TypeKind {
/// Elaboration-time types
ElabType(ElabKind),
/// Signal/Wire of generic width
2022-02-15 20:32:55 +00:00
Logic(ElabData),
/// UInt of generic width
2022-02-15 20:32:55 +00:00
UInt(ElabData),
/// Callable
2022-02-16 21:17:25 +00:00
Callable(FnSig),
2022-02-15 22:56:52 +00:00
/// A type that was not given and needs to be inferred
Infer,
/// A reference to a type variable as DeBruijn index
/// (scope, param)
TypeVar(u32, u32),
}
2022-02-16 21:17:25 +00:00
#[derive(Debug, Clone)]
pub struct FnSig {
params: Vec<Type>,
ret: Type,
}
2022-02-16 15:37:12 +00:00
#[derive(Debug, Clone)]
2022-02-15 22:56:52 +00:00
pub struct ElabData {
2022-02-15 20:32:55 +00:00
typ: Type,
value: ElabValue,
}
2022-02-16 15:37:12 +00:00
#[derive(Debug, Clone)]
2022-02-15 20:32:55 +00:00
enum ElabValue {
/// the value is not given and has to be inferred
Infer,
/// the value is given as some byte representation
2022-02-15 20:32:55 +00:00
Concrete(ElabValueData),
}
2022-02-16 15:37:12 +00:00
#[derive(Debug, Clone)]
2022-02-15 20:32:55 +00:00
enum ElabValueData {
U32(u32),
2022-02-15 20:32:55 +00:00
Bytes(Vec<u8>),
}
/// Types that are only valid during Elaboration
2022-02-06 22:19:55 +00:00
#[derive(Debug)]
enum ElabKind {
/// general, unsized number type
2022-01-23 21:52:06 +00:00
Num,
}
2022-02-16 15:37:12 +00:00
#[derive(Debug)]
pub enum GenericArg {
Elab(ElabData),
Type(Type),
}
2022-02-20 19:12:35 +00:00
#[derive(Debug)]
pub enum InferenceResult {
/// The first type was inferred
First(Type),
/// The second type was inferred
Second(Type),
/// A typevar was inferred
TypeVar(u32, u32, Type),
/// The types were incompatible
Incompatible,
/// Neither of the types were complete
Ambigous,
}
2022-02-15 20:32:55 +00:00
pub struct PrimitiveTypes {
pub elabnum: Type,
pub logic: Type,
2022-02-15 22:56:52 +00:00
pub infer: Type,
2022-02-15 20:32:55 +00:00
}
2022-02-15 20:32:55 +00:00
pub struct TypingContext {
types: Vec<TypeStruct>,
pub primitives: PrimitiveTypes,
}
2022-02-15 20:32:55 +00:00
impl TypingContext {
pub fn new() -> Self {
let primitives = PrimitiveTypes {
elabnum: InternedType(0),
logic: InternedType(1),
2022-02-15 22:56:52 +00:00
infer: InternedType(2),
2022-02-15 20:32:55 +00:00
};
Self {
2022-02-15 22:56:52 +00:00
types: vec![
TypeStruct {
kind: TypeKind::ElabType(ElabKind::Num),
},
TypeStruct {
kind: TypeKind::Logic(ElabData {
typ: primitives.elabnum,
value: ElabValue::Infer,
}),
},
TypeStruct {
kind: TypeKind::Infer,
},
],
2022-02-15 20:32:55 +00:00
primitives,
2022-02-06 20:02:55 +00:00
}
}
2022-02-15 20:32:55 +00:00
pub fn add(&mut self, typ: TypeStruct) -> Type {
let id = self.types.len();
self.types.push(typ);
InternedType(id)
2022-02-06 20:02:55 +00:00
}
2022-02-15 20:32:55 +00:00
pub fn get(&self, typ: Type) -> &TypeStruct {
&self.types[typ.0]
2022-02-06 22:19:55 +00:00
}
2022-02-16 15:37:12 +00:00
pub fn make_elabnum_u32(&self, num: u32) -> ElabData {
ElabData {
typ: self.primitives.elabnum,
value: ElabValue::Concrete(ElabValueData::U32(num)),
}
}
2022-02-18 11:59:53 +00:00
pub fn make_logic_size(&mut self, width: u32) -> Type {
let widthnum = self.make_elabnum_u32(width);
self.parameterize(self.primitives.logic, &[GenericArg::Elab(widthnum)])
.unwrap()
}
pub fn make_typevar(&mut self, dbi: u32, tvar: u32) -> Type {
self.add(TypeStruct {
kind: TypeKind::TypeVar(dbi, tvar),
})
}
2022-02-20 21:44:58 +00:00
pub fn get_width(&self, typ: Type) -> Option<u32> {
match &self.get(typ).kind {
TypeKind::ElabType(_) => None,
TypeKind::Logic(data) => match &data.value {
ElabValue::Infer => None,
ElabValue::Concrete(val) => match val {
ElabValueData::U32(val) => Some(*val),
ElabValueData::Bytes(_) => None,
},
},
TypeKind::UInt(_) => todo!(),
TypeKind::Callable(_) => None,
TypeKind::Infer => None,
TypeKind::TypeVar(_, _) => None,
}
}
2022-02-16 15:37:12 +00:00
pub fn parameterize(&mut self, typ: Type, params: &[GenericArg]) -> Option<Type> {
// TODO: return proper error type here
match &self.get(typ).kind {
// Elab types have no params yet
TypeKind::ElabType(_) => None,
TypeKind::Logic(_) => {
if params.len() != 1 {
// invalid number of typeargs
return None;
};
let param = &params[0];
if let GenericArg::Elab(data) = param {
if data.typ == self.primitives.elabnum {
Some(self.add(TypeStruct {
kind: TypeKind::Logic(data.clone()),
}))
} else {
// arg must be elabnum
None
}
} else {
// arg must be an elab value
None
}
}
TypeKind::UInt(_) => todo!(),
2022-02-16 21:17:25 +00:00
TypeKind::Callable(_sig) => todo!("callable generic params"),
2022-02-16 15:37:12 +00:00
// need to know what the type is to parameterize it
TypeKind::Infer | &TypeKind::TypeVar(_, _) => None,
}
}
2022-02-20 17:26:14 +00:00
/// Given the type of a variable in two locations, infer what the true type should be
2022-02-20 19:12:35 +00:00
pub fn infer_type(&mut self, typ_a: Type, typ_b: Type) -> InferenceResult {
2022-02-20 17:26:14 +00:00
match (&self.get(typ_a).kind, &self.get(typ_b).kind) {
2022-02-20 19:12:35 +00:00
(TypeKind::TypeVar(dbi, tvar), _) => InferenceResult::TypeVar(*dbi, *tvar, typ_b),
(_, TypeKind::TypeVar(dbi, tvar)) => InferenceResult::TypeVar(*dbi, *tvar, typ_a),
(a, b) => {
let a_full = self.is_fully_typed_kind(a);
let b_full = self.is_fully_typed_kind(b);
if a_full && b_full {
InferenceResult::Incompatible
} else if a_full && !b_full {
InferenceResult::Second(typ_a)
} else if !a_full && b_full {
InferenceResult::First(typ_b)
} else {
InferenceResult::Ambigous
}
}
2022-02-20 17:26:14 +00:00
}
}
2022-02-20 19:12:35 +00:00
fn is_fully_typed_kind(&self, kind: &TypeKind) -> bool {
match kind {
TypeKind::ElabType(_) => todo!(),
TypeKind::Logic(data) => {
if let ElabValue::Concrete(_) = data.value {
true
} else {
false
}
}
TypeKind::UInt(_) => todo!(),
TypeKind::Callable(_) => todo!(),
TypeKind::Infer => false,
TypeKind::TypeVar(dbi, _tvar) => {
// if the DeBruijn index is 0, there is no further information to gain
// from a surrounding scope
*dbi != 0
}
2022-02-16 15:37:12 +00:00
}
}
2022-02-20 19:12:35 +00:00
/// return whether the type has no unfilled parameters
pub fn is_fully_typed(&self, typ: Type) -> bool {
self.is_fully_typed_kind(&self.get(typ).kind)
}
2022-02-15 22:56:52 +00:00
pub fn pretty_value(&self, w: &mut dyn std::fmt::Write, data: &ElabData) -> std::fmt::Result {
2022-02-16 15:37:12 +00:00
match &data.value {
2022-02-15 22:56:52 +00:00
ElabValue::Infer => write!(w, "?: ")?,
2022-02-16 15:37:12 +00:00
ElabValue::Concrete(val) => match val {
ElabValueData::U32(val) => write!(w, "{:?}: ", val)?,
ElabValueData::Bytes(val) => write!(w, "{:?}: ", val)?,
},
2022-02-15 22:56:52 +00:00
}
self.pretty_type(w, data.typ)
}
2022-02-15 20:32:55 +00:00
pub fn pretty_type(&self, w: &mut dyn std::fmt::Write, typ: Type) -> std::fmt::Result {
match &self.get(typ).kind {
2022-02-15 22:56:52 +00:00
TypeKind::ElabType(val) => write!(w, "{:?}", val),
TypeKind::Logic(val) => {
let mut width = String::new();
self.pretty_value(&mut width, val)?;
write!(w, "Logic<{}>", width)
}
TypeKind::Infer => write!(w, "?"),
2022-02-15 20:44:10 +00:00
TypeKind::UInt(_) => todo!("print uint"),
2022-02-16 21:17:25 +00:00
TypeKind::Callable(_sig) => todo!("print callable"),
TypeKind::TypeVar(_, tvar) => write!(w, "T{}", tvar),
2022-02-06 20:02:55 +00:00
}
}
}