use crate::{
context::Shared,
types::TypeId,
value::{
Value, ValueId,
block::BlockId,
function::FunctionId,
util::base_ref::{BaseRef, WithShared},
},
};
use jstd::Identifier;
#[derive(Identifier)]
pub struct LiteralId(usize);
#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum SymbolicRef {
Block(BlockId),
Function(FunctionId),
String(String),
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Literal {
pub value: u64,
pub type_id: TypeId,
pub symbolic: Option<SymbolicRef>,
}
pub type LiteralRef<'str, 'ctx> = BaseRef<&'ctx Shared<'str>, LiteralId>;
impl<'s, 'ctx: 's, 'str: 'ctx> WithShared<'s, 'ctx, 'str> for LiteralRef<'str, 'ctx> {
fn shared(&'s self) -> &'ctx Shared<'str> {
self.ctx
}
}
impl<'s, 'ctx: 's, 'str: 'ctx, Ctx> BaseRef<Ctx, LiteralId>
where
Self: WithShared<'s, 'ctx, 'str>,
{
fn inner(&'s self) -> &'ctx Literal {
&self.shared().values.literals[self.id]
}
pub fn mask(&'s self) -> u64 {
let size = self.shared().types.size_of(self.inner().type_id);
if size >= 8 {
u64::MAX
} else {
(1u64 << (size * 8)) - 1
}
}
pub fn value(&'s self) -> u64 {
self.inner().value & self.mask()
}
pub fn type_id(&'s self) -> TypeId {
self.inner().type_id
}
}
impl std::fmt::Display for LiteralRef<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let literal = &self.ctx.values.literals[self.id];
match &literal.symbolic {
Some(SymbolicRef::Block(_)) | Some(SymbolicRef::Function(_)) => {
write!(f, "&<0x{:x}>", literal.value)
}
Some(SymbolicRef::String(s)) => write!(f, "&{:?}", s),
None if self.ctx.types.is_bool(literal.type_id) => {
write!(f, "{}", if literal.value != 0 { "true" } else { "false" })
}
None => write!(f, "0x{:x}", literal.value),
}
}
}
impl<'str, 'ctx> Value<'str, 'ctx> for LiteralRef<'str, 'ctx> {
fn id(&self) -> ValueId {
ValueId::Literal(self.id)
}
fn size(&self) -> usize {
self.ctx
.types
.size_of(self.ctx.values.literals[self.id].type_id)
}
}