use crate::{Block, Constant, Error, Value};
use hashbrown::HashMap;
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::collections::BTreeMap;
use std::fmt;
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ConstId(usize);
impl fmt::Display for ConstId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "C{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Var(usize);
impl fmt::Display for Var {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct StaticId(usize);
impl fmt::Display for StaticId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "v{}", self.0)
}
}
#[derive(Debug, Clone, Copy)]
struct SharedAssign {
id: StaticId,
block: BlockId,
}
#[derive(Debug, Clone)]
pub struct Assign {
shared: Rc<Cell<SharedAssign>>,
}
impl Assign {
#[inline]
pub(crate) fn new(id: StaticId, block: BlockId) -> Self {
Self {
shared: Rc::new(Cell::new(SharedAssign { id, block })),
}
}
pub(crate) fn replace(&self, other: &Self) {
self.shared.set(other.shared.get());
}
pub(crate) fn id(&self) -> StaticId {
self.shared.get().id
}
}
impl fmt::Display for Assign {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let shared = self.shared.get();
write!(f, "{}", shared.id)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct BlockId(usize);
impl fmt::Display for BlockId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "${}", self.0)
}
}
#[derive(Clone, Default)]
pub(crate) struct Global {
inner: Rc<GlobalInner>,
}
impl Global {
pub(crate) fn values(&self) -> Ref<'_, Values> {
self.inner.values.borrow()
}
pub(crate) fn values_mut(&self) -> RefMut<'_, Values> {
self.inner.values.borrow_mut()
}
pub(crate) fn mark_return(&self, block_id: BlockId) {
self.inner.returns.borrow_mut().push(block_id);
}
pub(crate) fn var(&self) -> Var {
let id = self.inner.value.get();
self.inner.value.set(id + 1);
Var(id)
}
pub(crate) fn static_id(&self) -> StaticId {
let id = self.inner.statics.get();
self.inner.statics.set(id + 1);
StaticId(id)
}
#[inline]
pub(crate) fn blocks(&self) -> Blocks<'_> {
Blocks {
blocks: self.inner.blocks.borrow(),
}
}
pub(crate) fn block(&self, name: Option<Box<str>>) -> Block {
let id = BlockId(self.inner.blocks.borrow().len());
let block = Block::new(id, self.clone(), name);
self.inner.blocks.borrow_mut().push(block.clone());
block
}
pub(crate) fn constant(&self, constant: Constant) -> ConstId {
let mut constants = self.inner.constants.borrow_mut();
return match constant {
Constant::Unit => ConstId(0),
c => {
let mut rev = self.inner.constants_rev.borrow_mut();
if let Some(const_id) = rev.get(&c) {
return *const_id;
}
let const_id = ConstId(constants.len());
rev.insert(c.clone(), const_id);
constants.push(c);
const_id
}
};
}
pub(crate) fn constants(&self) -> Ref<'_, [Constant]> {
Ref::map(self.inner.constants.borrow(), |c| c.as_slice())
}
}
#[derive(Default)]
pub(crate) struct Values {
values: BTreeMap<StaticId, Value>,
}
impl Values {
pub(crate) fn remove(&mut self, id: StaticId) -> Option<Value> {
self.values.remove(&id)
}
pub(crate) fn insert(&mut self, id: StaticId, value: Value) {
self.values.insert(id, value);
}
pub(crate) fn get(&self, id: StaticId) -> Option<&Value> {
self.values.get(&id)
}
pub(crate) fn get_mut(&mut self, id: StaticId) -> Option<&mut Value> {
self.values.get_mut(&id)
}
}
struct GlobalInner {
value: Cell<usize>,
statics: Cell<usize>,
blocks: RefCell<Vec<Block>>,
constants: RefCell<Vec<Constant>>,
constants_rev: RefCell<HashMap<Constant, ConstId>>,
returns: RefCell<Vec<BlockId>>,
pub(crate) values: RefCell<Values>,
}
impl Default for GlobalInner {
fn default() -> Self {
Self {
value: Default::default(),
statics: Default::default(),
blocks: Default::default(),
constants: RefCell::new(vec![Constant::Unit]),
constants_rev: Default::default(),
returns: RefCell::new(Vec::new()),
values: RefCell::new(Values::default()),
}
}
}
pub(crate) struct Blocks<'a> {
blocks: Ref<'a, Vec<Block>>,
}
impl Blocks<'_> {
pub(crate) fn get(&self, id: BlockId) -> Result<&Block, Error> {
match self.blocks.get(id.0) {
Some(block) => Ok(block),
None => Err(Error::MissingBlock(id)),
}
}
}