1use std::fmt::{self, Debug};
2
3use crate::{Expression, FieldId, Ident, Load, PcodeResolver, Range, TableId, pretty_print_ident};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum LabelOrNode<S = ()> {
11 Label(Box<str>),
17
18 Node(Box<str>),
21
22 Expr(Expression<S>),
24}
25
26impl<S> LabelOrNode<S> {
27 pub fn strip_span(self) -> LabelOrNode<()> {
29 match self {
30 LabelOrNode::Label(name) => LabelOrNode::Label(name),
31 LabelOrNode::Node(name) => LabelOrNode::Node(name),
32 LabelOrNode::Expr(expr) => LabelOrNode::Expr(expr.strip_span()),
33 }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43pub enum DelaySlotArg {
44 Bytes(u64),
46
47 Field(FieldId),
50
51 Deferred(Box<str>),
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60pub enum AstNode<S = ()> {
61 Assignment {
63 lhs: Ident,
65 size: Option<usize>,
68 rhs: Expression<S>,
70 },
71
72 LoadAssignment {
74 lhs: Load<S>,
76 size: Option<usize>,
79 rhs: Expression<S>,
81 },
82
83 RangeAssignment {
86 lhs: Range<S>,
88 size: Option<usize>,
90 rhs: Expression<S>,
92 },
93
94 Build(TableId),
99
100 DelaySlot(DelaySlotArg),
102
103 DeferredBuild(Box<str>),
106
107 Label(Box<str>),
109
110 Branch {
112 target: LabelOrNode<S>,
114 },
115
116 ConditionalBranch {
119 condition: Expression<S>,
121 target: LabelOrNode<S>,
123 },
124
125 BranchIndirect {
127 target: Expression<S>,
129 },
130
131 Call {
134 target: LabelOrNode<S>,
136 },
137
138 CallIndirect {
140 target: Expression<S>,
142 },
143
144 Return {
146 target: Expression<S>,
148 },
149
150 Export(Expression<S>),
155
156 Expression(Expression<S>),
159}
160
161impl AstNode {
162 pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
165 match self {
166 AstNode::Assignment { lhs, size, rhs } => format!(
167 "{}{} = {};",
168 pretty_print_ident(spec, lhs),
169 pretty_print_size(*size),
170 rhs.pretty_print(spec)
171 ),
172 AstNode::LoadAssignment { lhs, size, rhs } => format!(
173 "{}{} = {};",
174 lhs.pretty_print(spec),
175 pretty_print_size(*size),
176 rhs.pretty_print(spec)
177 ),
178 AstNode::RangeAssignment { lhs, size, rhs } => format!(
179 "{}{} = {};",
180 lhs.pretty_print(spec),
181 pretty_print_size(*size),
182 rhs.pretty_print(spec)
183 ),
184 AstNode::Build(table_id) => format!("build table{};", usize::from(*table_id)),
185 AstNode::DelaySlot(arg) => match arg {
186 DelaySlotArg::Bytes(n) => format!("delayslot({n});"),
187 DelaySlotArg::Field(id) => {
188 format!("delayslot({});", spec.field_name(*id))
189 }
190 DelaySlotArg::Deferred(name) => format!("delayslot({name});"),
191 },
192 AstNode::DeferredBuild(name) => format!("build {name};"),
193 AstNode::Label(name) => format!("<{name}>"),
194 AstNode::Branch { target } => format!("goto {};", pretty_print_target(spec, target)),
195 AstNode::ConditionalBranch { condition, target } => format!(
196 "if {} goto {};",
197 condition.pretty_print(spec),
198 pretty_print_target(spec, target)
199 ),
200 AstNode::BranchIndirect { target } => {
201 format!("goto [{}];", target.pretty_print(spec))
202 }
203 AstNode::Call { target } => format!("call {};", pretty_print_target(spec, target)),
204 AstNode::CallIndirect { target } => {
205 format!("call [{}];", target.pretty_print(spec))
206 }
207 AstNode::Return { target } => format!("return [{}];", target.pretty_print(spec)),
208 AstNode::Export(expr) => format!("export {};", expr.pretty_print(spec)),
209 AstNode::Expression(expr) => format!("{};", expr.pretty_print(spec)),
210 }
211 }
212}
213
214impl<S> AstNode<S> {
215 pub fn strip_span(self) -> AstNode<()> {
217 match self {
218 AstNode::Assignment { lhs, size, rhs } => AstNode::Assignment {
219 lhs,
220 size,
221 rhs: rhs.strip_span(),
222 },
223 AstNode::LoadAssignment { lhs, size, rhs } => AstNode::LoadAssignment {
224 lhs: lhs.strip_span(),
225 size,
226 rhs: rhs.strip_span(),
227 },
228 AstNode::RangeAssignment { lhs, size, rhs } => AstNode::RangeAssignment {
229 lhs: lhs.strip_span(),
230 size,
231 rhs: rhs.strip_span(),
232 },
233 AstNode::Build(table_id) => AstNode::Build(table_id),
234 AstNode::DelaySlot(arg) => AstNode::DelaySlot(arg),
235 AstNode::DeferredBuild(name) => AstNode::DeferredBuild(name),
236 AstNode::Label(name) => AstNode::Label(name),
237 AstNode::Branch { target } => AstNode::Branch {
238 target: target.strip_span(),
239 },
240 AstNode::ConditionalBranch { condition, target } => AstNode::ConditionalBranch {
241 condition: condition.strip_span(),
242 target: target.strip_span(),
243 },
244 AstNode::BranchIndirect { target } => AstNode::BranchIndirect {
245 target: target.strip_span(),
246 },
247 AstNode::Call { target } => AstNode::Call {
248 target: target.strip_span(),
249 },
250 AstNode::CallIndirect { target } => AstNode::CallIndirect {
251 target: target.strip_span(),
252 },
253 AstNode::Return { target } => AstNode::Return {
254 target: target.strip_span(),
255 },
256 AstNode::Export(expr) => AstNode::Export(expr.strip_span()),
257 AstNode::Expression(expr) => AstNode::Expression(expr.strip_span()),
258 }
259 }
260}
261
262#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
264pub struct Ast<S = ()> {
265 pub ty: AstNode<S>,
267 pub span: S,
270}
271
272impl<S: Debug> Debug for Ast<S> {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 self.ty.fmt(f)
275 }
276}
277
278impl<S> Ast<S> {
279 pub fn strip_span(self) -> Ast<()> {
281 Ast {
282 ty: self.ty.strip_span(),
283 span: (),
284 }
285 }
286}
287
288impl From<AstNode> for Ast {
289 fn from(ty: AstNode) -> Self {
290 Self { ty, span: () }
291 }
292}
293
294impl Ast {
295 pub fn pretty_print(&self, spec: &impl PcodeResolver) -> String {
298 self.ty.pretty_print(spec)
299 }
300}
301
302fn pretty_print_target(spec: &impl PcodeResolver, target: &LabelOrNode) -> String {
303 match target {
304 LabelOrNode::Label(name) => format!("<{name}>"),
305 LabelOrNode::Node(name) => (*name).to_string(),
306 LabelOrNode::Expr(expr) => expr.pretty_print(spec),
307 }
308}
309
310fn pretty_print_size(size: Option<usize>) -> String {
311 size.map(|size| format!(":{size}")).unwrap_or_default()
312}