1use crate::{
13 context::{Context, Shared},
14 space::Space,
15 value::{
16 BasicBlock, FunctionBody, LocalBlockId, LocalValueId, QCodeView, ValueId,
17 block::BlockId,
18 bytes::BytesRef,
19 function::FunctionId,
20 insn::{Callee, InstructionRef, Mnemonic},
21 literal::{LiteralId, LiteralRef, SymbolicRef},
22 varnode::Varnode,
23 },
24};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum TokenKind {
29 Type,
32 Variable,
34 BlockParam,
37 Varnode,
39 Literal,
41 Bytes,
43 Keyword,
45 Operator,
47 Punctuation,
49 Label,
51 Field,
53 Function,
56 Space,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum Link {
63 Value(ValueId),
64 Function(FunctionId),
65 Block(BlockId),
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct Token {
74 pub text: String,
75 pub kind: TokenKind,
76 pub link: Option<Link>,
77}
78
79impl Token {
80 fn new(text: impl Into<String>, kind: TokenKind, link: Option<Link>) -> Self {
81 Token {
82 text: text.into(),
83 kind,
84 link,
85 }
86 }
87}
88
89struct Seg<'ctx, 'str, R> {
91 view: R,
92 out: Vec<Token>,
93 marker: std::marker::PhantomData<&'ctx &'str ()>,
94}
95
96impl<'ctx, 'str: 'ctx, R> Seg<'ctx, 'str, R>
97where
98 R: QCodeView<'ctx, 'str>,
99{
100 fn push(&mut self, text: impl Into<String>, kind: TokenKind, link: Option<Link>) {
101 self.out.push(Token::new(text, kind, link));
102 }
103
104 fn kw(&mut self, text: &str) {
105 self.push(text, TokenKind::Keyword, None);
106 }
107
108 fn op(&mut self, text: impl Into<String>) {
109 self.push(text, TokenKind::Operator, None);
110 }
111
112 fn punct(&mut self, text: &str) {
113 self.push(text, TokenKind::Punctuation, None);
114 }
115
116 fn ty(&mut self, type_id: crate::types::TypeId) {
119 self.push(
120 format!("{} ", self.view.shared().types.type_name(type_id)),
121 TokenKind::Type,
122 None,
123 );
124 }
125
126 fn value(&mut self, id: ValueId) {
130 let link = Some(Link::Value(id));
131 match id {
138 ValueId::Instruction(iid) => {
139 let r = self.view.insn_ref(iid);
140 self.ty(r.type_id());
141 self.push(instruction_atom(self.view, iid), TokenKind::Variable, link);
142 }
143 ValueId::BlockParam(pid) => {
144 let r = self.view.param_ref(pid);
145 self.ty(r.type_id());
146 self.push(
147 block_param_atom(self.view, pid),
148 TokenKind::BlockParam,
149 link,
150 );
151 }
152 ValueId::Literal(lid) => {
153 let r = LiteralRef::from_id(self.view.shared(), lid);
154 self.ty(r.type_id());
155 self.push(literal_atom_view(self.view, lid), TokenKind::Literal, link);
159 }
160 ValueId::Bytes(bid) => {
161 let r = BytesRef::from_id(self.view.shared(), bid);
162 self.ty(r.type_id());
163 self.push(r.to_string(), TokenKind::Bytes, link);
164 }
165 ValueId::Varnode(vid) => {
166 let r = Varnode::from_id(self.view.shared(), vid);
167 self.push(format!("i{} ", r.size() * 8), TokenKind::Type, None);
168 self.push(r.to_string(), TokenKind::Varnode, link);
169 }
170 ValueId::Poison(pid) => {
171 let ty = self.view.shared().values.poisons[pid].type_id;
172 self.ty(ty);
173 self.push("poison".to_string(), TokenKind::Literal, link);
174 }
175 ValueId::Temp(id) => {
176 let r = self.view.temp_ref(id);
177 self.push(format!("i{} ", r.size() * 8), TokenKind::Type, None);
178 self.push(r.to_string(), TokenKind::Varnode, link);
179 }
180 ValueId::Function(fid) => {
181 let name = self.view.interface(fid).name.to_string();
182 self.push(
183 format!("<{name}>"),
184 TokenKind::Function,
185 Some(Link::Function(fid)),
186 );
187 }
188 ValueId::BasicBlock(bid) => {
189 let text = if self.view.owner().is_some_and(|o| o != bid.func) {
195 format!("<{bid}>")
196 } else {
197 self.view.block_ref(bid).to_string()
198 };
199 self.push(text, TokenKind::Label, Some(Link::Block(bid)));
200 }
201 }
202 }
203
204 fn bare_value(&mut self, id: ValueId) {
208 match id {
209 ValueId::Instruction(iid) => {
210 self.push(
211 instruction_atom(self.view, iid),
212 TokenKind::Variable,
213 Some(Link::Value(id)),
214 );
215 }
216 other => self.value(other),
217 }
218 }
219
220 fn branch_target(&mut self, func: FunctionId, target: LocalBlockId, args: &[LocalValueId]) {
225 let target = BlockId::new(func, target);
226 let block = self.view.block_ref(target);
227 let name = block.name().unwrap_or("unnamed");
228 self.push(
229 format!("<{name}"),
230 TokenKind::Label,
231 Some(Link::Block(target)),
232 );
233
234 let params = block.params().collect::<Vec<_>>();
235 for (i, &arg) in args.iter().enumerate() {
236 self.punct(" ");
237 match params.get(i) {
238 Some(param) => self.push(param.to_string(), TokenKind::BlockParam, None),
239 None => self.push(format!("@arg{i}"), TokenKind::BlockParam, None),
240 }
241 self.op("=");
242 self.value(arg.qualify(func));
243 }
244
245 self.push(">", TokenKind::Label, None);
246 }
247}
248
249fn instruction_atom<'ctx, 'str: 'ctx>(
251 view: impl QCodeView<'ctx, 'str>,
252 id: crate::value::InstructionId,
253) -> String {
254 match view.instruction(id).name.as_deref() {
255 Some(name) => format!("%{name}"),
256 None => format!("%tmp{:x}", usize::from(id.local)),
257 }
258}
259
260fn block_param_atom<'ctx, 'str: 'ctx>(
262 view: impl QCodeView<'ctx, 'str>,
263 id: crate::value::BlockParamId,
264) -> String {
265 let r = view.param_ref(id);
266 match r.name() {
267 Some(name) => format!("@{name}"),
268 None => format!("@param{:x}", usize::from(id.local)),
269 }
270}
271
272pub fn instruction_segments<'ctx, 'str: 'ctx, R>(insn: &InstructionRef<'str, 'ctx, R>) -> Vec<Token>
275where
276 R: QCodeView<'ctx, 'str>,
277{
278 let view = insn.view;
279 let mut seg = Seg {
280 view,
281 out: Vec::new(),
282 marker: std::marker::PhantomData,
283 };
284
285 if insn.size() != 0 {
288 seg.ty(insn.type_id());
289 seg.push(
290 instruction_atom(view, insn.id),
291 TokenKind::Variable,
292 Some(Link::Value(ValueId::Instruction(insn.id))),
293 );
294 seg.op(" = ");
295 }
296
297 match insn.mnemonic() {
298 Mnemonic::Tuple(t) => tuple_with_type(&mut seg, insn.id.func, t, insn.type_id()),
299 m => mnemonic_segments(&mut seg, insn.id.func, m),
300 }
301
302 seg.out
303}
304
305fn tuple_with_type<'ctx, 'str: 'ctx>(
306 seg: &mut Seg<'ctx, 'str, impl QCodeView<'ctx, 'str>>,
307 func: FunctionId,
308 t: &crate::value::insn::Tuple,
309 type_id: crate::types::TypeId,
310) {
311 seg.kw("pack");
312 seg.punct("(");
313 for (i, &field) in t.fields.iter().enumerate() {
314 if i > 0 {
315 seg.punct(", ");
316 }
317 let name = seg
318 .view
319 .shared()
320 .types
321 .field_name(type_id, i)
322 .map(str::to_owned)
323 .unwrap_or_else(|| format!("field{}", i + 1));
324 seg.push(name, TokenKind::Field, None);
325 seg.op("=");
326 seg.value(field.qualify(func));
327 }
328 seg.punct(");");
329}
330
331fn mnemonic_segments<'ctx, 'str: 'ctx>(
332 seg: &mut Seg<'ctx, 'str, impl QCodeView<'ctx, 'str>>,
333 func: FunctionId,
334 m: &Mnemonic,
335) {
336 use crate::value::insn::Unop;
337 match m {
338 Mnemonic::Load(l) => {
339 seg.kw("load");
340 seg.punct("(");
341 seg.push(space_name(seg.view, func, l.space), TokenKind::Space, None);
342 seg.punct(":");
343 seg.push(l.size.to_string(), TokenKind::Type, None);
344 seg.punct(", ");
345 seg.value(l.ptr.qualify(func));
346 seg.punct(");");
347 }
348 Mnemonic::Store(s) => {
349 seg.kw("store");
350 seg.punct("(");
351 seg.push(space_name(seg.view, func, s.space), TokenKind::Space, None);
352 seg.punct(":");
353 seg.push(s.size.to_string(), TokenKind::Type, None);
354 seg.punct(", ");
355 seg.value(s.ptr.qualify(func));
356 seg.op(" <- ");
357 seg.value(s.src.qualify(func));
358 seg.punct(");");
359 }
360 Mnemonic::Branch(b) => {
361 seg.kw("goto ");
362 seg.branch_target(func, b.target, &b.args);
363 seg.punct(";");
364 }
365 Mnemonic::BranchInd(b) => {
366 seg.kw("goto ");
367 seg.punct("[");
368 seg.value(b.ptr.qualify(func));
369 seg.punct("];");
370 }
371 Mnemonic::Switch(sw) => {
372 seg.kw("switch ");
373 seg.value(sw.scrutinee.qualify(func));
374 seg.punct(" { ");
375 for (i, case) in sw.cases.iter().enumerate() {
376 if i > 0 {
377 seg.punct(", ");
378 }
379 seg.push(format!("{:#x}", case.value), TokenKind::Literal, None);
380 seg.op(" => ");
381 seg.branch_target(func, case.target, &case.args);
382 }
383 if let Some(default) = sw.default {
384 if !sw.cases.is_empty() {
385 seg.punct(", ");
386 }
387 seg.kw("default");
388 seg.op(" => ");
389 seg.branch_target(func, default, &sw.default_args);
390 }
391 seg.punct(" };");
392 }
393 Mnemonic::CBranch(cb) => {
394 seg.kw("if ");
395 seg.value(cb.condition.qualify(func));
396 seg.kw(" goto ");
397 seg.branch_target(func, cb.success_block, &cb.success_args);
398 seg.kw(" else goto ");
399 seg.branch_target(func, cb.failure_block, &cb.failure_args);
400 seg.punct(";");
401 }
402 Mnemonic::Apply(a) => {
403 seg.kw("apply ");
404 let (target, link) = callee_name_link(seg.view, a.target);
405 seg.push(target, TokenKind::Function, link);
406 seg.punct("(");
407 for (i, &arg) in a.args.iter().enumerate() {
408 if i > 0 {
409 seg.punct(", ");
410 }
411 seg.value(arg.qualify(func));
412 }
413 seg.punct(");");
414 }
415 Mnemonic::Call(c) => {
416 seg.kw("call fn ");
417 let (target, link) = callee_name_link(seg.view, c.target);
418 seg.push(target, TokenKind::Function, link);
419 seg.punct("(");
420 for (i, &arg) in c.args.iter().enumerate() {
421 if i > 0 {
422 seg.punct(", ");
423 }
424 let arg_name = c
425 .target
426 .real()
427 .map(|target| call_arg_name(seg.view, target, i))
428 .unwrap_or_else(|| format!("@arg{i}="));
429 seg.push(arg_name, TokenKind::BlockParam, None);
430 seg.value(arg.qualify(func));
431 }
432 seg.punct(");");
433 }
434 Mnemonic::TailCall(tc) => {
435 seg.kw("tailcall fn ");
436 let (target, link) = callee_name_link(seg.view, tc.target);
437 seg.push(target, TokenKind::Function, link);
438 seg.punct("(");
439 for (i, &arg) in tc.args.iter().enumerate() {
440 if i > 0 {
441 seg.punct(", ");
442 }
443 seg.value(arg.qualify(func));
444 }
445 seg.punct(");");
446 }
447 Mnemonic::CallInd(c) => {
448 seg.kw("call ");
449 seg.punct("[");
450 seg.value(c.ptr.qualify(func));
451 seg.punct("]");
452 if !c.args.is_empty() {
453 seg.punct("(");
454 for (i, &arg) in c.args.iter().enumerate() {
455 if i > 0 {
456 seg.punct(", ");
457 }
458 seg.value(arg.qualify(func));
459 }
460 seg.punct(")");
461 }
462 seg.punct(";");
463 }
464 Mnemonic::BadInsn(_) => {
467 seg.kw("badinsn");
468 seg.punct(";");
469 }
470 Mnemonic::Return(r) => match r.value {
471 Some(value) => {
472 seg.kw("return ");
473 seg.value(value.qualify(func));
474 seg.kw(" at ");
475 seg.value(r.ptr.qualify(func));
476 seg.punct(";");
477 }
478 None => {
479 seg.kw("return at ");
480 seg.value(r.ptr.qualify(func));
481 seg.punct(";");
482 }
483 },
484 Mnemonic::ReturnValue(r) => {
485 seg.kw("return ");
486 seg.value(r.value.qualify(func));
487 seg.punct(";");
488 }
489 Mnemonic::Unop(u) => match u.op {
490 Unop::IntNegate | Unop::IntNot | Unop::FloatNegate => {
491 seg.op(format!("{} ", u.op));
492 seg.value(u.src.qualify(func));
493 seg.punct(";");
494 }
495 _ => {
496 seg.kw(&u.op.to_string());
497 seg.punct("(");
498 seg.value(u.src.qualify(func));
499 seg.punct(");");
500 }
501 },
502 Mnemonic::Binop(b) => {
503 seg.value(b.lhs.qualify(func));
504 seg.op(format!(" {} ", b.op));
505 seg.value(b.rhs.qualify(func));
506 seg.punct(";");
507 }
508 Mnemonic::Zext(z) => cast(seg, func, "zext", 'i', z.size, z.src),
509 Mnemonic::Sext(s) => cast(seg, func, "sext", 'i', s.size, s.src),
510 Mnemonic::IntToFloat(c) => cast(seg, func, "int2float", 'f', c.size, c.src),
511 Mnemonic::FloatToFloat(c) => cast(seg, func, "float2float", 'f', c.size, c.src),
512 Mnemonic::FloatToInt(c) => cast(seg, func, "trunc", 'i', c.size, c.src),
513 Mnemonic::Range(r) => {
514 seg.value(r.src.qualify(func));
515 seg.punct("[");
516 seg.push(r.start.to_string(), TokenKind::Literal, None);
517 seg.punct(":");
518 seg.push((r.start + r.size).to_string(), TokenKind::Literal, None);
519 seg.punct("];");
520 }
521 Mnemonic::IsFloatNaN(o) => unary_call(seg, func, "nan", o.src),
522 Mnemonic::LzCount(o) => unary_call(seg, func, "lzcount", o.src),
523 Mnemonic::PopCount(o) => unary_call(seg, func, "popcount", o.src),
524 Mnemonic::Carry(o) => binary_call(seg, func, "carry", o.lhs, o.rhs),
525 Mnemonic::SCarry(o) => binary_call(seg, func, "scarry", o.lhs, o.rhs),
526 Mnemonic::SBorrow(o) => binary_call(seg, func, "sborrow", o.lhs, o.rhs),
527 Mnemonic::Assert(a) => {
528 seg.kw("assert ");
529 seg.value(a.condition.qualify(func));
530 seg.punct(";");
531 }
532 Mnemonic::Tuple(t) => {
535 seg.kw("pack");
536 seg.punct("(");
537 for (i, &field) in t.fields.iter().enumerate() {
538 if i > 0 {
539 seg.punct(", ");
540 }
541 seg.push(format!("field{}", i + 1), TokenKind::Field, None);
542 seg.op("=");
543 seg.value(field.qualify(func));
544 }
545 seg.punct(");");
546 }
547 Mnemonic::Extract(e) => {
548 seg.kw("extract");
549 seg.punct("(");
550 seg.bare_value(e.agg.qualify(func));
551 let name = e
552 .field_name_view(seg.view, func)
553 .map(str::to_owned)
554 .unwrap_or_else(|| format!("field{}", e.index + 1));
555 seg.push(format!(".{name}"), TokenKind::Field, None);
556 seg.punct(");");
557 }
558 Mnemonic::Gep(g) => {
559 seg.kw("gep");
560 seg.punct("(");
561 seg.bare_value(g.base.qualify(func));
562 match g.field_name_view(seg.view, func) {
563 Some(name) => seg.push(format!(".{name}"), TokenKind::Field, None),
564 None => {
565 seg.op(" + ");
566 seg.push(format!("{:#x}", g.offset), TokenKind::Literal, None);
567 }
568 }
569 seg.punct(");");
570 }
571 Mnemonic::Map(map) => {
572 let (body, link) = callee_name_link(seg.view, map.body);
573 if map.captures.is_empty() {
574 seg.push(body, TokenKind::Function, link);
575 seg.op(" <$> ");
576 seg.value(map.src.qualify(func));
577 seg.punct(";");
578 } else {
579 seg.punct("(");
580 seg.push(body, TokenKind::Function, link);
581 for &c in &map.captures {
582 seg.punct(" ");
583 seg.value(c.qualify(func));
584 }
585 seg.op(") <$> ");
586 seg.value(map.src.qualify(func));
587 seg.punct(";");
588 }
589 }
590 Mnemonic::Scan(scan) => {
591 let (body, link) = callee_name_link(seg.view, scan.body);
592 let body = match scan.body {
593 Callee::Real(_) => format!("@{body}"),
594 Callee::Minted(_) => body,
595 };
596 if scan.captures.is_empty() {
597 seg.kw("scanl ");
598 seg.push(body, TokenKind::Function, link);
599 seg.punct(" ");
600 seg.value(scan.init.qualify(func));
601 seg.punct(" ");
602 seg.value(scan.src.qualify(func));
603 seg.punct(";");
604 } else {
605 seg.kw("scanl ");
606 seg.punct("(");
607 seg.push(body, TokenKind::Function, link);
608 for &c in &scan.captures {
609 seg.punct(" ");
610 seg.value(c.qualify(func));
611 }
612 seg.punct(") ");
613 seg.value(scan.init.qualify(func));
614 seg.punct(" ");
615 seg.value(scan.src.qualify(func));
616 seg.punct(";");
617 }
618 }
619 Mnemonic::PCodeOp(p) => {
620 let op = seg.view.shared().pcode_ops[p.id].to_string();
621 if let Some(dst) = p.dst {
622 seg.value(dst.qualify(func));
623 seg.op(" = ");
624 }
625 seg.kw(&op);
626 seg.punct("(");
627 for (i, &arg) in p.args.iter().enumerate() {
628 if i > 0 {
629 seg.punct(", ");
630 }
631 seg.value(arg.qualify(func));
632 }
633 seg.punct(");");
634 }
635 Mnemonic::Intrinsic(intr) => {
636 seg.kw(&format!("${}", intr.id.name()));
637 seg.punct("(");
638 for (i, &arg) in intr.args.iter().enumerate() {
639 if i > 0 {
640 seg.punct(", ");
641 }
642 seg.value(arg.qualify(func));
643 }
644 seg.punct(");");
645 }
646 }
647}
648
649fn cast<'ctx, 'str: 'ctx>(
650 seg: &mut Seg<'ctx, 'str, impl QCodeView<'ctx, 'str>>,
651 func: FunctionId,
652 kw: &str,
653 prefix: char,
654 size: usize,
655 src: LocalValueId,
656) {
657 seg.kw(kw);
658 seg.punct("(");
659 seg.push(format!("{prefix}{}", size * 8), TokenKind::Type, None);
660 seg.punct(", ");
661 seg.value(src.qualify(func));
662 seg.punct(");");
663}
664
665fn unary_call<'ctx, 'str: 'ctx>(
666 seg: &mut Seg<'ctx, 'str, impl QCodeView<'ctx, 'str>>,
667 func: FunctionId,
668 kw: &str,
669 src: LocalValueId,
670) {
671 seg.kw(kw);
672 seg.punct("(");
673 seg.value(src.qualify(func));
674 seg.punct(");");
675}
676
677fn binary_call<'ctx, 'str: 'ctx>(
678 seg: &mut Seg<'ctx, 'str, impl QCodeView<'ctx, 'str>>,
679 func: FunctionId,
680 kw: &str,
681 lhs: LocalValueId,
682 rhs: LocalValueId,
683) {
684 seg.kw(kw);
685 seg.punct("(");
686 seg.value(lhs.qualify(func));
687 seg.punct(", ");
688 seg.value(rhs.qualify(func));
689 seg.punct(");");
690}
691
692fn space_name<'ctx, 'str: 'ctx>(
695 view: impl QCodeView<'ctx, 'str>,
696 func: FunctionId,
697 space: crate::space::LocalMemorySpaceId,
698) -> String {
699 match space.qualify(func) {
700 crate::space::MemorySpaceId::Shared(space) => {
701 let space_ref = Space::from_id(view.shared(), space);
702 match space_ref.name.as_deref() {
703 Some(name) => name.to_string(),
704 None => format!("space: {space}"),
705 }
706 }
707 crate::space::MemorySpaceId::Temp(space) => {
712 format!("$temp{}", usize::from(space.local))
713 }
714 }
715}
716
717fn call_arg_name<'ctx, 'str: 'ctx>(
720 view: impl QCodeView<'ctx, 'str>,
721 target: FunctionId,
722 index: usize,
723) -> String {
724 let foreign = view.owner().is_some_and(|owner| owner != target);
731 let name = if foreign {
732 view.interface(target)
733 .signature
734 .as_ref()
735 .and_then(|s| s.extern_interface.as_ref())
736 .and_then(|iface| iface.args.get(index))
737 .and_then(|a| a.name.as_ref().map(|n| n.to_string()))
738 } else {
739 view.function_ref(target).input_arg_name(index)
740 };
741 match name {
742 Some(name) => format!("@{name}="),
743 None => format!("@arg{index}="),
744 }
745}
746
747fn callee_name_link<'ctx, 'str: 'ctx>(
750 view: impl QCodeView<'ctx, 'str>,
751 callee: Callee,
752) -> (String, Option<Link>) {
753 match callee {
754 Callee::Real(id) => (
755 view.interface(id).name.to_string(),
756 Some(Link::Function(id)),
757 ),
758 Callee::Minted(slot) => (format!("<minted:{slot}>"), None),
759 }
760}
761
762pub fn value_tokens(ctx: &Context<'_>, id: ValueId) -> Vec<Token> {
766 let mut seg = Seg {
767 view: crate::value::ModuleView::new(ctx),
768 out: Vec::new(),
769 marker: std::marker::PhantomData,
770 };
771 seg.value(id);
772 seg.out
773}
774
775pub fn value_tokens_view<'ctx, 'str: 'ctx, R>(view: R, id: ValueId) -> Vec<Token>
777where
778 R: QCodeView<'ctx, 'str>,
779{
780 let link = Some(Link::Value(id));
781 let shared = view.shared();
782 let mut out = Vec::new();
783 let mut typed = |type_id, text: String, kind| {
784 out.push(Token::new(
785 format!("{} ", shared.types.type_name(type_id)),
786 TokenKind::Type,
787 None,
788 ));
789 out.push(Token::new(text, kind, link));
790 };
791
792 match id {
793 ValueId::Instruction(iid) => {
794 let insn = view.instruction(iid);
795 let atom = insn.name.as_deref().map_or_else(
796 || {
797 let local: usize = iid.local.into();
798 format!("%tmp{local:x}")
799 },
800 |name| format!("%{name}"),
801 );
802 typed(insn.type_id, atom, TokenKind::Variable);
803 }
804 ValueId::BlockParam(pid) => {
805 let param = view.block_param(pid);
806 let atom = param.name.as_deref().map_or_else(
807 || {
808 let local: usize = pid.local.into();
809 format!("@param{local:x}")
810 },
811 |name| format!("@{name}"),
812 );
813 typed(param.type_id, atom, TokenKind::BlockParam);
814 }
815 ValueId::Literal(lid) => {
816 let literal = &shared.values.literals[lid];
817 let atom = literal_atom_view(view, lid);
818 typed(literal.type_id, atom, TokenKind::Literal);
819 }
820 ValueId::Bytes(id) => {
821 let value = BytesRef::from_id(shared, id);
822 typed(value.type_id(), value.to_string(), TokenKind::Bytes);
823 }
824 ValueId::Varnode(id) => {
825 let value = Varnode::from_id(shared, id);
826 out.push(Token::new(
827 format!("i{} ", value.size() * 8),
828 TokenKind::Type,
829 None,
830 ));
831 out.push(Token::new(value.to_string(), TokenKind::Varnode, link));
832 }
833 ValueId::Temp(id) => {
834 let value = view.temp_ref(id);
835 out.push(Token::new(
836 format!("i{} ", value.size() * 8),
837 TokenKind::Type,
838 None,
839 ));
840 out.push(Token::new(value.to_string(), TokenKind::Varnode, link));
841 }
842 ValueId::Function(id) => out.push(Token::new(
843 format!("<{}>", view.interface(id).name),
844 TokenKind::Function,
845 Some(Link::Function(id)),
846 )),
847 ValueId::BasicBlock(id) => out.push(Token::new(
848 view.block_ref(id).to_string(),
849 TokenKind::Label,
850 Some(Link::Block(id)),
851 )),
852 ValueId::Poison(id) => {
853 typed(
854 shared.values.poisons[id].type_id,
855 "poison".to_string(),
856 TokenKind::Literal,
857 );
858 }
859 }
860 out
861}
862
863pub fn literal_atom(ctx: &Context<'_>, id: LiteralId) -> String {
871 let literal = &ctx.shared.values.literals[id];
872 match &literal.symbolic {
873 Some(SymbolicRef::Block(bid)) => match BasicBlock::from_id(ctx, *bid).name() {
874 Some(name) => format!("&<{}>", name),
875 None => format!("&<0x{:x}>", literal.value),
876 },
877 Some(SymbolicRef::Function(fid)) => {
878 format!("&<{}>", FunctionBody::from_id(ctx, *fid).name())
879 }
880 Some(SymbolicRef::String(s)) => format!("&{:?}", s),
881 None if ctx.shared.types.is_bool(literal.type_id) => {
882 (if literal.value != 0 { "true" } else { "false" }).to_string()
883 }
884 None => format!("0x{:x}", literal.value),
885 }
886}
887
888fn literal_atom_view<'ctx, 'str: 'ctx>(view: impl QCodeView<'ctx, 'str>, id: LiteralId) -> String {
889 let shared = view.shared();
890 let literal = &shared.values.literals[id];
891 match &literal.symbolic {
892 Some(SymbolicRef::Block(id)) if view.owner().is_some_and(|o| o != id.func) => {
898 format!("&<0x{:x}>", literal.value)
899 }
900 Some(SymbolicRef::Block(id)) => view.block_ref(*id).name().map_or_else(
901 || format!("&<0x{:x}>", literal.value),
902 |name| format!("&<{name}>"),
903 ),
904 Some(SymbolicRef::Function(id)) => format!("&<{}>", view.interface(*id).name),
905 Some(SymbolicRef::String(value)) => format!("&{value:?}"),
906 None if shared.types.is_bool(literal.type_id) => {
907 (if literal.value != 0 { "true" } else { "false" }).to_string()
908 }
909 None => format!("0x{:x}", literal.value),
910 }
911}
912
913pub fn value_tokens_shared(shared: &Shared<'_>, id: ValueId) -> Vec<Token> {
920 let link = Some(Link::Value(id));
921 let mut out = Vec::new();
922 match id {
923 ValueId::Literal(lid) => {
924 let r = LiteralRef::from_id(shared, lid);
925 out.push(Token::new(
926 format!("{} ", shared.types.type_name(r.type_id())),
927 TokenKind::Type,
928 None,
929 ));
930 out.push(Token::new(r.to_string(), TokenKind::Literal, link));
931 }
932 ValueId::Bytes(bid) => {
933 let r = BytesRef::from_id(shared, bid);
934 out.push(Token::new(
935 format!("{} ", shared.types.type_name(r.type_id())),
936 TokenKind::Type,
937 None,
938 ));
939 out.push(Token::new(r.to_string(), TokenKind::Bytes, link));
940 }
941 ValueId::Varnode(vid) => {
942 let r = Varnode::from_id(shared, vid);
943 out.push(Token::new(
944 format!("i{} ", r.size() * 8),
945 TokenKind::Type,
946 None,
947 ));
948 out.push(Token::new(r.to_string(), TokenKind::Varnode, link));
949 }
950 ValueId::Poison(pid) => {
951 let ty = shared.values.poisons[pid].type_id;
952 out.push(Token::new(
953 format!("{} ", shared.types.type_name(ty)),
954 TokenKind::Type,
955 None,
956 ));
957 out.push(Token::new("poison".to_string(), TokenKind::Literal, link));
958 }
959 _ => panic!("value_tokens_shared: not a shared-leaf value id"),
960 }
961 out
962}