use midenc_session::LibraryPath;
use crate::{
IdentAttr, Op, OpParser, OpPrinter, Operation, RegionKind, RegionKindInterface, Symbol,
SymbolManager, SymbolManagerMut, SymbolMap, SymbolName, SymbolRef, SymbolTable, SymbolUseList,
UnsafeIntrusiveEntityRef, Usable, Visibility,
derive::operation,
dialects::builtin::{self, BuiltinDialect},
traits::{
GraphRegionNoTerminator, HasOnlyGraphRegion, IsolatedFromAbove, NoRegionArguments,
NoTerminator, SingleBlock, SingleRegion,
},
};
pub type InterfaceRef = UnsafeIntrusiveEntityRef<Interface>;
#[operation(
dialect = BuiltinDialect,
traits(
SingleRegion,
SingleBlock,
NoRegionArguments,
NoTerminator,
HasOnlyGraphRegion,
GraphRegionNoTerminator,
IsolatedFromAbove,
),
implements(RegionKindInterface, SymbolTable, Symbol, OpPrinter)
)]
pub struct Interface {
#[attr]
name: IdentAttr,
#[region]
body: RegionRef,
#[default]
symbols: SymbolMap,
#[default]
uses: SymbolUseList,
}
impl OpPrinter for Interface {
fn print(&self, printer: &mut crate::print::AsmPrinter<'_>) {
printer.print_space();
printer.print_symbol_name(self.get_name().as_symbol());
printer.print_space();
printer.print_region(&self.body());
}
}
impl OpParser for Interface {
fn parse(
state: &mut crate::OperationState,
parser: &mut dyn crate::OpAsmParser<'_>,
) -> crate::ParseResult {
let name = parser.parse_symbol_name()?;
state.add_attribute("name", parser.context_rc().create_attribute::<IdentAttr, _>(name));
let region = parser.context().create_region();
parser.parse_region(region, &[], true)?;
state.add_region(region);
Ok(())
}
}
impl RegionKindInterface for Interface {
#[inline(always)]
fn kind(&self) -> RegionKind {
RegionKind::Graph
}
}
impl Usable for Interface {
type Use = crate::SymbolUse;
#[inline(always)]
fn uses(&self) -> &SymbolUseList {
&self.uses
}
#[inline(always)]
fn uses_mut(&mut self) -> &mut SymbolUseList {
&mut self.uses
}
}
impl Symbol for Interface {
#[inline(always)]
fn as_symbol_operation(&self) -> &Operation {
&self.op
}
#[inline(always)]
fn as_symbol_operation_mut(&mut self) -> &mut Operation {
&mut self.op
}
fn name(&self) -> SymbolName {
Interface::name(self).as_symbol()
}
fn set_name(&mut self, name: SymbolName) {
Interface::set_name(self, name)
}
fn visibility(&self) -> Visibility {
Visibility::Public
}
fn set_visibility(&mut self, visibility: Visibility) {
assert_eq!(
visibility,
Visibility::Public,
"cannot give interfaces a visibility other than public"
);
}
}
impl SymbolTable for Interface {
#[inline(always)]
fn as_symbol_table_operation(&self) -> &Operation {
&self.op
}
#[inline(always)]
fn as_symbol_table_operation_mut(&mut self) -> &mut Operation {
&mut self.op
}
fn symbol_manager(&self) -> SymbolManager<'_> {
SymbolManager::new(&self.op, crate::Symbols::Borrowed(&self.symbols))
}
fn symbol_manager_mut(&mut self) -> SymbolManagerMut<'_> {
SymbolManagerMut::new(&mut self.op, crate::SymbolsMut::Borrowed(&mut self.symbols))
}
#[inline]
fn get(&self, name: SymbolName) -> Option<SymbolRef> {
self.symbols.get(name)
}
}
impl Interface {
pub fn library_path(&self) -> Option<LibraryPath> {
let parent = self.as_operation().parent_op()?;
let parent = parent.borrow();
let component = parent
.downcast_ref::<builtin::Component>()
.expect("invalid parent for interface operation: expected component");
let component_id = component.id();
let mut path = component_id.to_library_path();
let name = self.name().as_str();
let suffix = LibraryPath::new(&name).expect("invalid interface module name");
path.push(suffix.as_path());
Some(path)
}
}