mod ids;
mod ops;
mod types;
pub use ids::LocalVarInterner;
pub use ids::{Builtin, LocalVarId};
pub use ops::{BinaryOperator, UnaryOperator};
pub use types::{Binop, Load, Range, RangeParam, SpaceRef, Unop};
use crate::{BitRangeFieldId, FieldId, PCodeOpId, PMacroId, RegisterId, TableId};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Ident {
Named(LocalVarId),
Register(RegisterId),
BitRange(BitRangeFieldId),
Field(FieldId),
Table(TableId),
Global(Box<str>),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ExpressionTy<S = ()> {
SizedInt {
value: u64,
size: Option<usize>,
},
SubPieceMsb {
src: Box<Expression<S>>,
count: usize,
},
SubPieceLsb {
src: Box<Expression<S>>,
count: usize,
},
Load(Load<S>),
Range(Range<S>),
FunctionCall {
builtin: Builtin,
args: Vec<Expression<S>>,
},
PcodeOp {
id: PCodeOpId,
args: Vec<Expression<S>>,
},
MacroCall {
id: PMacroId,
args: Vec<Expression<S>>,
},
DeferredCall {
name: Box<str>,
args: Vec<Expression<S>>,
},
Ident(Ident),
Unop(Unop<S>),
Binop(Binop<S>),
}
impl From<ExpressionTy> for Expression {
fn from(ty: ExpressionTy) -> Self {
Self {
ty,
size: None,
span: (),
}
}
}
impl ExpressionTy {
pub fn with_size(self, size: usize) -> Expression {
Expression {
ty: self,
size: Some(size),
span: (),
}
}
pub(crate) fn pretty_print(&self, spec: &impl crate::PcodeResolver) -> String {
match self {
ExpressionTy::SizedInt { value, size } => match size {
Some(size) => format!("{value}:{size}"),
None => value.to_string(),
},
ExpressionTy::SubPieceMsb { src, count } => {
format!("subpiece_msb({}, {})", src.pretty_print(spec), count)
}
ExpressionTy::SubPieceLsb { src, count } => {
format!("subpiece_lsb({}, {})", src.pretty_print(spec), count)
}
ExpressionTy::Load(load) => load.pretty_print(spec),
ExpressionTy::Range(range) => range.pretty_print(spec),
ExpressionTy::FunctionCall { builtin, args } => {
format!("{}({})", builtin.as_str(), pretty_print_args(args, spec))
}
ExpressionTy::PcodeOp { id, args } => format!(
"{}({})",
spec.pcode_op_name(*id),
pretty_print_args(args, spec)
),
ExpressionTy::MacroCall { id, args } => format!(
"{}({})",
spec.macro_name(*id),
pretty_print_args(args, spec)
),
ExpressionTy::DeferredCall { name, args } => {
format!("{}({})", name, pretty_print_args(args, spec))
}
ExpressionTy::Ident(ident) => pretty_print_ident(spec, ident),
ExpressionTy::Unop(unop) => unop.pretty_print(spec),
ExpressionTy::Binop(binop) => binop.pretty_print(spec),
}
}
}
impl<S> ExpressionTy<S> {
pub fn strip_span(self) -> ExpressionTy<()> {
match self {
ExpressionTy::SizedInt { value, size } => ExpressionTy::SizedInt { value, size },
ExpressionTy::SubPieceMsb { src, count } => ExpressionTy::SubPieceMsb {
src: Box::new(src.strip_span()),
count,
},
ExpressionTy::SubPieceLsb { src, count } => ExpressionTy::SubPieceLsb {
src: Box::new(src.strip_span()),
count,
},
ExpressionTy::Load(load) => ExpressionTy::Load(load.strip_span()),
ExpressionTy::Range(range) => ExpressionTy::Range(range.strip_span()),
ExpressionTy::FunctionCall { builtin, args } => ExpressionTy::FunctionCall {
builtin,
args: args.into_iter().map(Expression::strip_span).collect(),
},
ExpressionTy::PcodeOp { id, args } => ExpressionTy::PcodeOp {
id,
args: args.into_iter().map(Expression::strip_span).collect(),
},
ExpressionTy::MacroCall { id, args } => ExpressionTy::MacroCall {
id,
args: args.into_iter().map(Expression::strip_span).collect(),
},
ExpressionTy::DeferredCall { name, args } => ExpressionTy::DeferredCall {
name,
args: args.into_iter().map(Expression::strip_span).collect(),
},
ExpressionTy::Ident(ident) => ExpressionTy::Ident(ident),
ExpressionTy::Unop(unop) => ExpressionTy::Unop(unop.strip_span()),
ExpressionTy::Binop(binop) => ExpressionTy::Binop(binop.strip_span()),
}
}
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Expression<S = ()> {
pub ty: ExpressionTy<S>,
pub size: Option<usize>,
pub span: S,
}
impl<S: std::fmt::Debug> std::fmt::Debug for Expression<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(size) = self.size {
write!(f, "{:?} (size: {:?})", self.ty, size)
} else {
self.ty.fmt(f)
}
}
}
impl<S> Expression<S> {
pub fn strip_span(self) -> Expression<()> {
Expression {
ty: self.ty.strip_span(),
size: self.size,
span: (),
}
}
}
impl Expression {
pub fn pretty_print(&self, spec: &impl crate::PcodeResolver) -> String {
self.ty.pretty_print(spec)
}
}
impl Expression<(usize, usize)> {
pub fn new_int(value: u64, size: Option<usize>, span: (usize, usize)) -> Self {
Self {
ty: ExpressionTy::SizedInt { value, size },
size,
span,
}
}
}
fn pretty_print_args(args: &[Expression], spec: &impl crate::PcodeResolver) -> String {
args.iter()
.map(|arg| arg.pretty_print(spec))
.collect::<Vec<_>>()
.join(", ")
}
pub fn pretty_print_ident(spec: &impl crate::PcodeResolver, ident: &Ident) -> String {
match ident {
Ident::Named(id) => format!("v{}", id.0),
Ident::Register(_) => spec.ident_name(ident),
Ident::BitRange(_) => spec.ident_name(ident),
Ident::Field(_) => spec.ident_name(ident),
Ident::Table(id) => format!("table{}", usize::from(*id)),
Ident::Global(name) => format!("?{name}"),
}
}