use crate::{BinaryOperator, Expression, PcodeResolver, SpaceId, UnaryOperator};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum SpaceRef {
Resolved(SpaceId),
Deferred(Box<str>),
}
impl SpaceRef {
pub fn resolved(&self) -> SpaceId {
match self {
SpaceRef::Resolved(id) => *id,
SpaceRef::Deferred(name) => panic!("unresolved space `{name}` reached runtime"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RangeParam {
Literal(usize),
MacroArg(crate::LocalVarId),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Range<S = ()> {
pub value: Box<Expression<S>>,
pub start: RangeParam,
pub size: RangeParam,
}
impl<S> Range<S> {
pub fn strip_span(self) -> Range<()> {
Range {
value: Box::new(self.value.strip_span()),
start: self.start,
size: self.size,
}
}
}
impl Range {
pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
format!(
"range({}, {}, {})",
self.value.pretty_print(spec),
pretty_print_range_param(&self.start),
pretty_print_range_param(&self.size)
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Load<S = ()> {
pub space: Option<SpaceRef>,
pub size: Option<usize>,
pub ptr: Box<Expression<S>>,
}
impl<S> Load<S> {
pub fn strip_span(self) -> Load<()> {
Load {
space: self.space,
size: self.size,
ptr: Box::new(self.ptr.strip_span()),
}
}
}
impl Load {
pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
let mut parts = Vec::new();
if let Some(space) = &self.space {
let name = match space {
SpaceRef::Resolved(id) => pretty_print_space(spec, *id),
SpaceRef::Deferred(name) => format!("?{name}"),
};
parts.push(format!("space={name}"));
}
if let Some(size) = self.size {
parts.push(format!("size={size}"));
}
parts.push(format!("ptr={}", self.ptr.pretty_print(spec)));
format!("load({})", parts.join(", "))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Unop<S = ()> {
pub op: UnaryOperator,
pub e: Box<Expression<S>>,
}
impl<S> Unop<S> {
pub fn strip_span(self) -> Unop<()> {
Unop {
op: self.op,
e: Box::new(self.e.strip_span()),
}
}
}
impl Unop {
pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
let expr = self.e.pretty_print(spec);
match self.op {
UnaryOperator::LogicalNot => format!("!{expr}"),
UnaryOperator::BitwiseNot => format!("~{expr}"),
UnaryOperator::Minus => format!("-{expr}"),
UnaryOperator::FloatMinus => format!("f-{expr}"),
UnaryOperator::AddressOf(Some(size)) => format!("&:{size} {expr}"),
UnaryOperator::AddressOf(None) => format!("&{expr}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Binop<S = ()> {
pub op: BinaryOperator,
pub lhs: Box<Expression<S>>,
pub rhs: Box<Expression<S>>,
}
impl<S> Binop<S> {
pub fn strip_span(self) -> Binop<()> {
Binop {
op: self.op,
lhs: Box::new(self.lhs.strip_span()),
rhs: Box::new(self.rhs.strip_span()),
}
}
}
impl Binop {
pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
format!(
"({} {} {})",
self.lhs.pretty_print(spec),
self.op.pretty_print(),
self.rhs.pretty_print(spec)
)
}
}
fn pretty_print_range_param(param: &RangeParam) -> String {
match param {
RangeParam::Literal(value) => value.to_string(),
RangeParam::MacroArg(id) => format!("arg{}", id.0),
}
}
fn pretty_print_space(spec: &impl PcodeResolver, id: SpaceId) -> String {
spec.space_name(id)
}