1use std::{borrow::Cow, slice};
26
27pub use crate::instruction::{Emitter, Planner, SizeInference};
28use crate::{
29 AstNode, BinaryOperator, Builtin, Expression, ExpressionTy, Ident, LabelOrNode, Load,
30 PCodeOpId, PcodeSpaceRef, RangeParam, SpaceId, UnaryOperator,
31};
32
33pub trait ExprNode: Copy {
40 type Args: Iterator<Item = Self> + ExactSizeIterator + Clone;
42
43 fn size(self) -> Option<usize>;
49
50 fn kind<'a>(self) -> ExprKind<'a, Self>
55 where
56 Self: 'a;
57}
58
59#[derive(Debug, Clone)]
62pub enum ExprKind<'a, E: ExprNode> {
63 SizedInt {
65 value: u64,
67 size: Option<usize>,
69 },
70 Ident(Ident),
72 Load(LoadNode<'a, E>),
74 Range(RangeNode<E>),
76 SubPieceMsb {
78 src: E,
80 count: usize,
82 },
83 SubPieceLsb {
85 src: E,
87 count: usize,
89 },
90 FunctionCall {
92 builtin: Builtin,
94 args: E::Args,
96 },
97 PcodeOp {
99 id: PCodeOpId,
101 args: E::Args,
103 },
104 Unop {
106 op: UnaryOperator,
108 e: E,
110 },
111 Binop {
113 op: BinaryOperator,
115 lhs: E,
117 rhs: E,
119 },
120 Internal(&'static str),
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum LoadSpace<'a> {
129 Default,
131 Resolved(SpaceId),
133 Deferred(&'a str),
137}
138
139impl<'a> From<&'a Option<PcodeSpaceRef>> for LoadSpace<'a> {
140 fn from(space: &'a Option<PcodeSpaceRef>) -> Self {
141 match space {
142 None => LoadSpace::Default,
143 Some(PcodeSpaceRef::Resolved(id)) => LoadSpace::Resolved(*id),
144 Some(PcodeSpaceRef::Deferred(name)) => LoadSpace::Deferred(name),
145 }
146 }
147}
148
149impl From<LoadSpace<'_>> for Option<PcodeSpaceRef> {
150 fn from(space: LoadSpace<'_>) -> Self {
152 match space {
153 LoadSpace::Default => None,
154 LoadSpace::Resolved(id) => Some(PcodeSpaceRef::Resolved(id)),
155 LoadSpace::Deferred(name) => Some(PcodeSpaceRef::Deferred(name.into())),
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy)]
162pub struct LoadNode<'a, E> {
163 pub space: LoadSpace<'a>,
165 pub size: Option<usize>,
167 pub ptr: E,
169}
170
171impl<'a, E> LoadNode<'a, E> {
172 fn from_load<S>(load: &'a Load<S>, node: impl FnOnce(&'a Expression<S>) -> E) -> Self {
173 Self {
174 space: (&load.space).into(),
175 size: load.size,
176 ptr: node(&load.ptr),
177 }
178 }
179}
180
181#[derive(Debug, Clone, Copy)]
183pub struct RangeNode<E> {
184 pub value: E,
186 pub start: RangeParam,
188 pub size: RangeParam,
190}
191
192#[derive(Debug, Clone)]
194pub enum TargetNode<'a, E> {
195 Label(Cow<'a, str>),
197 Node(&'a str),
200 Expr(E),
202}
203
204impl<'a, S> From<&'a LabelOrNode<S>> for TargetNode<'a, &'a Expression<S>> {
205 fn from(target: &'a LabelOrNode<S>) -> Self {
206 match target {
207 LabelOrNode::Label(name) => TargetNode::Label(Cow::Borrowed(name)),
208 LabelOrNode::Node(name) => TargetNode::Node(name),
209 LabelOrNode::Expr(expr) => TargetNode::Expr(expr),
210 }
211 }
212}
213
214#[derive(Debug, Clone)]
217pub enum StmtKind<'a, E: ExprNode> {
218 Assignment {
220 lhs: Ident,
222 size: Option<usize>,
224 rhs: E,
226 },
227 LoadAssignment {
229 load: LoadNode<'a, E>,
231 size: Option<usize>,
233 rhs: E,
235 },
236 RangeAssignment {
238 range: RangeNode<E>,
240 size: Option<usize>,
242 rhs: E,
244 },
245 Label(Cow<'a, str>),
247 Branch {
249 target: TargetNode<'a, E>,
251 },
252 ConditionalBranch {
254 condition: E,
256 target: TargetNode<'a, E>,
258 },
259 BranchIndirect {
261 target: E,
263 },
264 Call {
266 target: TargetNode<'a, E>,
268 },
269 CallIndirect {
271 target: E,
273 },
274 Return {
276 target: E,
278 },
279 Expression(E),
281 Internal(&'static str),
285}
286
287impl<'a, S> From<&'a AstNode<S>> for StmtKind<'a, &'a Expression<S>> {
288 fn from(statement: &'a AstNode<S>) -> Self {
289 match statement {
290 AstNode::Assignment { lhs, size, rhs } => StmtKind::Assignment {
291 lhs: lhs.clone(),
292 size: *size,
293 rhs,
294 },
295 AstNode::LoadAssignment { lhs, size, rhs } => StmtKind::LoadAssignment {
296 load: LoadNode::from_load(lhs, |ptr| ptr),
297 size: *size,
298 rhs,
299 },
300 AstNode::RangeAssignment { lhs, size, rhs } => StmtKind::RangeAssignment {
301 range: RangeNode {
302 value: &lhs.value,
303 start: lhs.start,
304 size: lhs.size,
305 },
306 size: *size,
307 rhs,
308 },
309 AstNode::Build(_) => StmtKind::Internal("build statement"),
310 AstNode::DelaySlot(_) => StmtKind::Internal("delay-slot directive"),
311 AstNode::DeferredBuild(_) => StmtKind::Internal("deferred build statement"),
312 AstNode::Label(name) => StmtKind::Label(Cow::Borrowed(name)),
313 AstNode::Branch { target } => StmtKind::Branch {
314 target: target.into(),
315 },
316 AstNode::ConditionalBranch { condition, target } => StmtKind::ConditionalBranch {
317 condition,
318 target: target.into(),
319 },
320 AstNode::BranchIndirect { target } => StmtKind::BranchIndirect { target },
321 AstNode::Call { target } => StmtKind::Call {
322 target: target.into(),
323 },
324 AstNode::CallIndirect { target } => StmtKind::CallIndirect { target },
325 AstNode::Return { target } => StmtKind::Return { target },
326 AstNode::Export(_) => StmtKind::Internal("export statement"),
327 AstNode::Expression(expr) => StmtKind::Expression(expr),
328 }
329 }
330}
331
332impl<'a, S> ExprNode for &'a Expression<S> {
333 type Args = slice::Iter<'a, Expression<S>>;
334
335 fn size(self) -> Option<usize> {
336 self.size
337 }
338
339 fn kind<'b>(self) -> ExprKind<'b, Self>
340 where
341 Self: 'b,
342 {
343 match &self.ty {
344 ExpressionTy::SizedInt { value, size } => ExprKind::SizedInt {
345 value: *value,
346 size: *size,
347 },
348 ExpressionTy::Ident(ident) => ExprKind::Ident(ident.clone()),
349 ExpressionTy::Load(load) => ExprKind::Load(LoadNode::from_load(load, |ptr| ptr)),
350 ExpressionTy::Range(range) => ExprKind::Range(RangeNode {
351 value: &range.value,
352 start: range.start,
353 size: range.size,
354 }),
355 ExpressionTy::SubPieceMsb { src, count } => {
356 ExprKind::SubPieceMsb { src, count: *count }
357 }
358 ExpressionTy::SubPieceLsb { src, count } => {
359 ExprKind::SubPieceLsb { src, count: *count }
360 }
361 ExpressionTy::FunctionCall { builtin, args } => ExprKind::FunctionCall {
362 builtin: *builtin,
363 args: args.iter(),
364 },
365 ExpressionTy::PcodeOp { id, args } => ExprKind::PcodeOp {
366 id: *id,
367 args: args.iter(),
368 },
369 ExpressionTy::MacroCall { .. } => ExprKind::Internal("macro call"),
370 ExpressionTy::DeferredCall { .. } => ExprKind::Internal("deferred call"),
371 ExpressionTy::Unop(unop) => ExprKind::Unop {
372 op: unop.op,
373 e: &unop.e,
374 },
375 ExpressionTy::Binop(binop) => ExprKind::Binop {
376 op: binop.op,
377 lhs: &binop.lhs,
378 rhs: &binop.rhs,
379 },
380 }
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::{ExprKind, ExprNode, LoadSpace, StmtKind};
387 use crate::{
388 AstNode, Expression, ExpressionTy, Ident, Load, PcodeSpaceRef, RegisterId, SpaceId,
389 };
390
391 fn load(space: Option<PcodeSpaceRef>) -> Expression {
392 Expression {
393 ty: ExpressionTy::Load(Load {
394 space,
395 size: Some(4),
396 ptr: Box::new(Expression {
397 ty: ExpressionTy::Ident(Ident::Register(RegisterId::new(0))),
398 size: Some(8),
399 span: (),
400 }),
401 }),
402 size: Some(4),
403 span: (),
404 }
405 }
406
407 #[test]
410 fn deferred_load_space_keeps_its_name() {
411 let deferred = Some(PcodeSpaceRef::Deferred("segment".into()));
412 let expr = load(deferred.clone());
413 let ExprKind::Load(node) = (&expr).kind() else {
414 panic!("a load");
415 };
416 assert_eq!(node.space, LoadSpace::Deferred("segment"));
417 assert_eq!(Option::<PcodeSpaceRef>::from(node.space), deferred);
418
419 let store = AstNode::LoadAssignment {
420 lhs: Load {
421 space: deferred.clone(),
422 size: Some(4),
423 ptr: Box::new(expr.clone()),
424 },
425 size: None,
426 rhs: expr,
427 };
428 let StmtKind::LoadAssignment { load, .. } = StmtKind::from(&store) else {
429 panic!("a store");
430 };
431 assert_eq!(load.space, LoadSpace::Deferred("segment"));
432
433 assert_eq!(
434 LoadSpace::from(&Some(PcodeSpaceRef::Resolved(SpaceId::new(3)))),
435 LoadSpace::Resolved(SpaceId::new(3))
436 );
437 assert_eq!(LoadSpace::from(&None), LoadSpace::Default);
438 }
439}