use super::ProtoStatement;
use super::variable::native_bytes;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SiteKind {
Static,
Dynamic,
Wide,
}
#[derive(Debug, Clone)]
pub struct SiteInfo {
pub current_offset: u32,
pub width_bits: u32,
pub native_bytes: u8,
pub kind: SiteKind,
}
#[derive(Debug, Default, Clone)]
pub struct SiteTable {
pub sites: Vec<SiteInfo>,
}
impl SiteTable {
pub fn new() -> Self {
Self::default()
}
fn push(&mut self, info: SiteInfo) -> u32 {
let id = self.sites.len() as u32;
self.sites.push(info);
id
}
pub fn add_static(&mut self, current_offset: u32, width_bits: u32, native_bytes: u8) -> u32 {
self.push(SiteInfo {
current_offset,
width_bits,
native_bytes,
kind: SiteKind::Static,
})
}
pub fn add_dynamic(
&mut self,
base_current_offset: u32,
width_bits: u32,
native_bytes: u8,
) -> u32 {
self.push(SiteInfo {
current_offset: base_current_offset,
width_bits,
native_bytes,
kind: SiteKind::Dynamic,
})
}
pub fn add_wide(&mut self, current_offset: u32, width_bits: u32, native_bytes: u8) -> u32 {
self.push(SiteInfo {
current_offset,
width_bits,
native_bytes,
kind: SiteKind::Wide,
})
}
pub fn len(&self) -> usize {
self.sites.len()
}
pub fn is_empty(&self) -> bool {
self.sites.is_empty()
}
}
impl SiteTable {
pub fn extend_from_protos(&mut self, protos: &[ProtoStatement]) {
for s in protos {
visit(s, self);
}
}
}
fn visit(stmt: &ProtoStatement, table: &mut SiteTable) {
match stmt {
ProtoStatement::Assign(a) if a.dst.is_ff() => {
let nb = native_bytes(a.dst_width);
let width = a.dst_width as u32;
let cur = a.dst_ff_current_offset as u32;
if a.dst_width > 64 {
table.add_wide(cur, width, nb as u8);
} else {
table.add_static(cur, width, nb as u8);
}
}
ProtoStatement::AssignDynamic(a) if a.dst_base.is_ff() => {
let nb = native_bytes(a.dst_width);
let width = a.dst_width as u32;
let base = a.dst_ff_current_base_offset as u32;
table.add_dynamic(base, width, nb as u8);
}
ProtoStatement::If(i) => {
for s in &i.true_side {
visit(s, table);
}
for s in &i.false_side {
visit(s, table);
}
}
ProtoStatement::For(f) => {
for s in &f.body {
visit(s, table);
}
}
ProtoStatement::SequentialBlock(body) => {
for s in body {
visit(s, table);
}
}
_ => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_table() {
let t = SiteTable::new();
assert_eq!(t.len(), 0);
assert!(t.is_empty());
}
#[test]
fn add_static_assigns_increasing_ids() {
let mut t = SiteTable::new();
assert_eq!(t.add_static(0, 32, 4), 0);
assert_eq!(t.add_static(8, 64, 8), 1);
assert_eq!(t.len(), 2);
}
#[test]
fn add_mixed_kinds() {
let mut t = SiteTable::new();
let s0 = t.add_static(0, 32, 4);
let s1 = t.add_dynamic(8, 64, 8);
let s2 = t.add_wide(16, 128, 16);
assert_eq!(s0, 0);
assert_eq!(s1, 1);
assert_eq!(s2, 2);
assert_eq!(t.sites[0].kind, SiteKind::Static);
assert_eq!(t.sites[1].kind, SiteKind::Dynamic);
assert_eq!(t.sites[2].kind, SiteKind::Wide);
}
#[test]
fn extend_from_empty_proto_list() {
let mut t = SiteTable::new();
t.extend_from_protos(&[]);
assert!(t.is_empty());
}
}