use crate::{
expr::{Expr, Flow, ToExpr},
intern::Interned,
module::{IncompleteDeclaration, NameId, ScopedNameId, StmtDeclaration, StmtWire},
source_location::SourceLocation,
ty::{CanonicalType, Type},
};
use std::{cell::RefCell, fmt, rc::Rc};
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Wire<T: Type> {
name: ScopedNameId,
source_location: SourceLocation,
ty: T,
}
impl<T: Type + fmt::Debug> fmt::Debug for Wire<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Wire({:?}: ", self.name)?;
self.ty.fmt(f)?;
f.write_str(")")
}
}
impl<T: Type> Wire<T> {
pub fn canonical(&self) -> Wire<CanonicalType> {
let Self {
name,
source_location,
ref ty,
} = *self;
Wire {
name,
source_location,
ty: ty.canonical(),
}
}
pub fn ty(&self) -> T {
self.ty
}
pub fn new_unchecked(
scoped_name: ScopedNameId,
source_location: SourceLocation,
ty: T,
) -> Self {
Self {
name: scoped_name,
source_location,
ty,
}
}
pub fn source_location(&self) -> SourceLocation {
self.source_location
}
pub fn containing_module_name(&self) -> Interned<str> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0
}
pub fn name(&self) -> Interned<str> {
self.name_id().0
}
pub fn name_id(&self) -> NameId {
self.name.1
}
pub fn scoped_name(&self) -> ScopedNameId {
self.name
}
pub fn flow(&self) -> Flow {
Flow::Duplex
}
pub fn must_connect_to(&self) -> bool {
true
}
}
#[derive(Clone)]
pub struct IncompleteWire {
pub(crate) declaration: Rc<RefCell<IncompleteDeclaration>>,
}
impl IncompleteWire {
#[track_caller]
pub fn complete<T: Type>(&mut self, ty: T) -> Expr<T> {
let canonical_type = ty.canonical();
let mut declaration = self.declaration.borrow_mut();
if let IncompleteDeclaration::Incomplete {
name,
source_location,
} = *declaration
{
*declaration = IncompleteDeclaration::Complete(
StmtWire {
annotations: (),
wire: Wire {
name,
source_location,
ty: canonical_type,
},
}
.into(),
);
}
match *declaration {
IncompleteDeclaration::Complete(StmtDeclaration::Wire(StmtWire {
wire:
Wire {
name,
source_location,
ty: wire_ty,
},
..
})) => {
drop(declaration);
assert_eq!(wire_ty, canonical_type, "type mismatch");
Wire {
name,
source_location,
ty,
}
.to_expr()
}
IncompleteDeclaration::Taken => panic!("can't use wire outside of containing module"),
IncompleteDeclaration::Complete(_) | IncompleteDeclaration::Incomplete { .. } => {
unreachable!()
}
}
}
}