1use crate::opcodes::*;
2use crate::{Chunk, GVm, VMError, VMResult, Value};
3
4#[macro_export]
5macro_rules! decode_u8_enum {
6 ($code:expr) => {{
7 if let Some((_, val)) = $code.next() {
8 Ok(val)
9 } else {
10 Err($crate::VMError::new_chunk(
11 "Error decoding a u8 from chunk stream, missing operand.",
12 ))
13 }
14 }};
15}
16
17#[cfg(test)]
18#[macro_export]
19macro_rules! decode_chunk_u16 {
20 ($code:expr) => {{
21 if let (Some(idx1), Some(idx2)) = ($code.next(), $code.next()) {
22 Ok(((*idx1 as u16) << 8) | (*idx2 as u16))
23 } else {
24 Err($crate::VMError::new_chunk(
25 "Error decoding a u16 from chunk stream.",
26 ))
27 }
28 }};
29}
30
31#[macro_export]
32macro_rules! decode_u16_enum {
33 ($code:expr) => {{
34 if let (Some((_, idx1)), Some((_, idx2))) = ($code.next(), $code.next()) {
35 Ok(((idx1 as u16) << 8) | (idx2 as u16))
36 } else {
37 Err($crate::VMError::new_chunk(
38 "Error decoding a u16 from chunk stream.",
39 ))
40 }
41 }};
42}
43
44#[macro_export]
45macro_rules! decode_u32_enum {
46 ($code:expr) => {{
47 if let (Some((_, idx1)), Some((_, idx2)), Some((_, idx3)), Some((_, idx4))) =
48 ($code.next(), $code.next(), $code.next(), $code.next())
49 {
50 Ok(
51 ((idx1 as u32) << 24)
52 | ((idx2 as u32) << 16)
53 | ((idx3 as u32) << 8)
54 | (idx4 as u32),
55 )
56 } else {
57 Err($crate::VMError::new_chunk(
58 "Error decoding a u32 from chunk stream.",
59 ))
60 }
61 }};
62}
63
64macro_rules! disassemble_operand {
65 ($code:expr, $register:expr, $wide:expr) => {{
66 if $register {
67 if $wide {
68 print!("R({:#06x})", decode_u16_enum!($code)?);
69 } else {
70 print!("R({:#04x})", decode_u8_enum!($code)?);
71 }
72 } else {
73 if $wide {
74 print!("K({:#06x})", decode_u16_enum!($code)?);
75 } else {
76 print!("K({:#04x})", decode_u8_enum!($code)?);
77 }
78 }
79 }};
80}
81
82macro_rules! disassemble_immediate {
83 ($code:expr, $wide:expr) => {{
84 if $wide {
85 print!("{:#06x}", decode_u16_enum!($code)?);
86 } else {
87 print!("{:#04x}", decode_u8_enum!($code)?);
88 }
89 }};
90}
91
92macro_rules! disassemble_immediate_global {
93 ($code:expr, $wide:expr, $vm:expr) => {{
94 if $wide {
95 let idx = decode_u32_enum!($code)?;
96 print!("{idx:#010x}");
97 } else {
98 let idx = decode_u16_enum!($code)?;
99 print!("{idx:#06x}");
100 }
101 }};
102}
103
104macro_rules! disassemble_jump_operand {
105 ($chunk:expr, $code:expr, $wide:expr) => {{
106 let idx = if $wide {
107 let idx = decode_u16_enum!($code)?;
108 print!("J({idx:#06x})\t");
109 idx as usize
110 } else {
111 let idx = decode_u8_enum!($code)?;
112 print!("J({idx:#04x})\t");
113 idx as usize
114 };
115 print!("{:#010x}", $chunk.jump_table[idx]);
116 }};
117}
118
119impl Chunk {
120 fn disassemble_instruction<I, ENV>(
121 &self,
122 chunk: I,
123 op: OpCode,
124 wide: bool,
125 _vm: &GVm<ENV>,
126 ) -> VMResult<bool>
127 where
128 I: IntoIterator<Item = (usize, u8)>,
129 {
130 let mut code = chunk.into_iter();
131 match op {
132 NOP => {
133 println!("NOP({NOP:#04x})");
134 Ok(false)
135 }
136 HALT => {
137 println!("HALT({HALT:#04x})");
138 Ok(false)
139 }
140 RET => {
141 println!("RET({RET:#04x})");
142 Ok(false)
143 }
144 SRET => {
145 print!("SRET({SRET:#04x}) \t");
146 disassemble_operand!(code, true, wide);
147 println!();
148 Ok(false)
149 }
150 WIDE => {
151 println!("WIDE({WIDE:#04x})");
152 Ok(true)
153 }
154 MOV => {
155 print!("MOV({MOV:#04x}) \t");
156 disassemble_operand!(code, true, wide);
157 print!("\t");
158 disassemble_operand!(code, true, wide);
159 println!();
160 Ok(false)
161 }
162 MOVI => {
163 print!("MOVI({MOVI:#04x}) \t");
164 print!("R[");
165 disassemble_operand!(code, true, wide);
166 print!("]");
167 print!("\t");
168 disassemble_operand!(code, true, wide);
169 println!();
170 Ok(false)
171 }
172 MOVII => {
173 print!("MOVII({MOVII:#04x}) \t");
174 disassemble_operand!(code, true, wide);
175 print!("\t");
176 print!("R[");
177 disassemble_operand!(code, true, wide);
178 print!("]");
179 println!();
180 Ok(false)
181 }
182 GET => {
183 print!("GET({GET:#04x}) \t");
184 disassemble_operand!(code, true, wide);
185 print!("\t");
186 disassemble_operand!(code, true, wide);
187 print!("\t");
188 disassemble_operand!(code, true, wide);
189 println!();
190 Ok(false)
191 }
192 SETCOL => {
193 print!("SETCOL({SETCOL:#04x})\t");
194 disassemble_operand!(code, true, wide);
195 print!("\t");
196 disassemble_operand!(code, true, wide);
197 print!("\t");
198 disassemble_operand!(code, true, wide);
199 println!();
200 Ok(false)
201 }
202 SET => {
203 print!("SET({SET:#04x}) \t");
204 disassemble_operand!(code, true, wide);
205 print!("\t");
206 disassemble_operand!(code, true, wide);
207 println!();
208 Ok(false)
209 }
210 CONST => {
211 print!("CONST({CONST:#04x}) \t");
212 disassemble_operand!(code, true, wide);
213 print!("\t");
214 disassemble_operand!(code, false, wide);
215 println!();
216 Ok(false)
217 }
218 DEF => {
219 print!("DEF({DEF:#04x}) \t");
220 disassemble_operand!(code, true, wide);
221 print!("\t");
222 print!("G[");
223 disassemble_immediate_global!(code, wide, _vm);
224 println!("]");
225 Ok(false)
226 }
227 DEFV => {
228 print!("DEFV({DEFV:#04x}) \t");
229 disassemble_operand!(code, true, wide);
230 print!("\t");
231 print!("G[");
232 disassemble_immediate_global!(code, wide, _vm);
233 println!("]");
234 Ok(false)
235 }
236 REFI => {
237 print!("REFI({REFI:#04x}) \t");
238 disassemble_operand!(code, true, wide);
239 print!("\t");
240 print!("G[");
241 disassemble_immediate_global!(code, wide, _vm);
242 println!("]");
243 Ok(false)
244 }
245 CLRREG => {
246 print!("CLRREG({CLRREG:#04x}) \t");
247 disassemble_operand!(code, true, wide);
248 println!();
249 Ok(false)
250 }
251 REGT => {
252 print!("REGT({REGT:#04x}) \t");
253 disassemble_operand!(code, true, wide);
254 println!();
255 Ok(false)
256 }
257 REGF => {
258 print!("REGF({REGF:#04x}) \t");
259 disassemble_operand!(code, true, wide);
260 println!();
261 Ok(false)
262 }
263 REGN => {
264 print!("REGN({REGN:#04x}) \t");
265 disassemble_operand!(code, true, wide);
266 println!();
267 Ok(false)
268 }
269 REGC => {
270 print!("REGC({REGC:#04x}) \t");
271 disassemble_operand!(code, true, wide);
272 println!();
273 Ok(false)
274 }
275 REGB => {
276 print!("REGB({REGB:#04x}) \t");
277 disassemble_operand!(code, true, wide);
278 print!("\t");
279 disassemble_immediate!(code, wide);
280 println!();
281 Ok(false)
282 }
283 REGI => {
284 print!("REGI({REGI:#04x}) \t");
285 disassemble_operand!(code, true, wide);
286 print!("\t");
287 disassemble_immediate!(code, wide);
288 println!();
289 Ok(false)
290 }
291 CLOSE => {
292 print!("CLOSE({CLOSE:#04x}) \t");
293 disassemble_operand!(code, true, wide);
294 print!("\t");
295 disassemble_operand!(code, true, wide);
296 println!();
297 Ok(false)
298 }
299 BMOV => {
300 print!("BMOV({BMOV:#04x}) \t");
301 disassemble_operand!(code, true, wide);
302 print!("\t");
303 disassemble_operand!(code, true, wide);
304 print!("\t");
305 disassemble_immediate!(code, wide);
306 println!();
307 Ok(false)
308 }
309 LDSC => {
310 print!("LDSC({LDSC:#04x}) \t");
311 disassemble_operand!(code, true, wide);
312 print!("\t");
313 disassemble_immediate!(code, wide);
314 print!("\t");
315 disassemble_operand!(code, true, wide);
316 println!();
317 Ok(false)
318 }
319 LDSCR => {
320 print!("LDSCR({LDSCR:#04x}) \t");
321 disassemble_operand!(code, true, wide);
322 print!("\t");
323 disassemble_immediate!(code, wide);
324 print!("\t");
325 disassemble_operand!(code, true, wide);
326 println!();
327 Ok(false)
328 }
329 MDSC => {
330 print!("MDSC({MDSC:#04x}) \t");
331 disassemble_operand!(code, true, wide);
332 print!("\t");
333 disassemble_immediate!(code, wide);
334 print!("\t");
335 disassemble_operand!(code, true, wide);
336 println!();
337 Ok(false)
338 }
339 COPY => {
340 print!("COPY({COPY:#04x}) \t");
341 disassemble_operand!(code, true, wide);
342 print!("\t");
343 disassemble_operand!(code, true, wide);
344 println!();
345 Ok(false)
346 }
347 FRZ => {
348 print!("FRZ({FRZ:#04x}) \t");
349 disassemble_operand!(code, true, wide);
350 println!();
351 Ok(false)
352 }
353 CALL => {
354 print!("CALL({CALL:#04x}) \t");
355 disassemble_operand!(code, true, wide);
356 print!("\t");
357 disassemble_immediate!(code, wide);
358 print!("\t");
359 disassemble_operand!(code, true, wide);
360 println!();
361 Ok(false)
362 }
363 CALLG => {
364 print!("CALLG({CALLG:#04x}) \t");
365 print!("G[");
366 disassemble_immediate_global!(code, wide, _vm);
367 print!("]");
368 print!("\t");
369 disassemble_immediate!(code, wide);
370 print!("\t");
371 disassemble_operand!(code, true, wide);
372 println!();
373 Ok(false)
374 }
375 TCALL => {
376 print!("TCALL({TCALL:#04x}) \t");
377 disassemble_operand!(code, true, wide);
378 print!("\t");
379 disassemble_immediate!(code, wide);
380 println!();
381 Ok(false)
382 }
383 TCALLG => {
384 print!("TCALLG({TCALLG:#04x}) \t");
385 print!("G[");
386 disassemble_immediate_global!(code, wide, _vm);
387 print!("]");
388 print!("\t");
389 disassemble_immediate!(code, wide);
390 println!();
391 Ok(false)
392 }
393 CALLM => {
394 print!("CALLM({CALLM:#04x}) \t");
395 disassemble_immediate!(code, wide);
396 print!("\t");
397 disassemble_operand!(code, true, wide);
398 println!();
399 Ok(false)
400 }
401 TCALLM => {
402 print!("TCALLM({TCALLM:#04x}) \t");
403 disassemble_immediate!(code, wide);
404 println!();
405 Ok(false)
406 }
407 EQ => {
408 print!("EQ \t");
409 disassemble_operand!(code, true, wide);
410 print!("\t");
411 disassemble_operand!(code, true, wide);
412 print!("\t");
413 disassemble_operand!(code, true, wide);
414 println!();
415 Ok(false)
416 }
417 EQUAL => {
418 print!("EQUAL \t");
419 disassemble_operand!(code, true, wide);
420 print!("\t");
421 disassemble_operand!(code, true, wide);
422 print!("\t");
423 disassemble_operand!(code, true, wide);
424 println!();
425 Ok(false)
426 }
427 NOT => {
428 print!("NOT \t");
429 disassemble_operand!(code, true, wide);
430 print!("\t");
431 disassemble_operand!(code, true, wide);
432 println!();
433 Ok(false)
434 }
435 ERR => {
436 print!("ERR \t");
437 disassemble_operand!(code, true, wide);
438 print!("\t");
439 disassemble_operand!(code, true, wide);
440 println!();
441 Ok(false)
442 }
443 MKERR => {
444 print!("MKERR \t");
445 disassemble_operand!(code, true, wide);
446 print!("\t");
447 disassemble_operand!(code, true, wide);
448 print!("\t");
449 disassemble_operand!(code, true, wide);
450 println!();
451 Ok(false)
452 }
453 ISERR => {
454 print!("ISERR \t");
455 disassemble_operand!(code, true, wide);
456 print!("\t");
457 disassemble_operand!(code, true, wide);
458 println!();
459 Ok(false)
460 }
461 ISOK => {
462 print!("ISOK \t");
463 disassemble_operand!(code, true, wide);
464 print!("\t");
465 disassemble_operand!(code, true, wide);
466 println!();
467 Ok(false)
468 }
469 CCC => {
470 print!("CCC \t");
471 disassemble_operand!(code, true, wide);
472 print!("\t");
473 disassemble_operand!(code, true, wide);
474 println!();
475 Ok(false)
476 }
477 DFR => {
478 print!("DFR \t");
479 disassemble_operand!(code, true, wide);
480 println!();
481 Ok(false)
482 }
483 DFRPOP => {
484 println!("DFRPOP");
485 Ok(false)
486 }
487 ONERR => {
488 print!("ONERR \t");
489 disassemble_operand!(code, true, wide);
490 println!();
491 Ok(false)
492 }
493 JMP => {
494 print!("JMP({JMP:#04x}) \t");
495 disassemble_jump_operand!(self, code, wide);
496 println!();
497 Ok(false)
498 }
499 JMPT => {
500 print!("JMPT({JMPT:#04x}) \t");
501 disassemble_operand!(code, true, wide);
502 print!("\t");
503 disassemble_jump_operand!(self, code, wide);
504 println!();
505 Ok(false)
506 }
507 JMPF => {
508 print!("JMPF({JMPF:#04x}) \t");
509 disassemble_operand!(code, true, wide);
510 print!("\t");
511 disassemble_jump_operand!(self, code, wide);
512 println!();
513 Ok(false)
514 }
515 JMPEQ => {
516 print!("JMPEQ({JMPEQ:#04x}) \t");
517 disassemble_operand!(code, true, wide);
518 print!("\t");
519 disassemble_operand!(code, true, wide);
520 print!("\t");
521 disassemble_jump_operand!(self, code, wide);
522 println!();
523 Ok(false)
524 }
525 JMPLT => {
526 print!("JMPLT({JMPLT:#04x}) \t");
527 disassemble_operand!(code, true, wide);
528 print!("\t");
529 disassemble_operand!(code, true, wide);
530 print!("\t");
531 disassemble_jump_operand!(self, code, wide);
532 println!();
533 Ok(false)
534 }
535 JMPGT => {
536 print!("JMPGT({JMPGT:#04x}) \t");
537 disassemble_operand!(code, true, wide);
538 print!("\t");
539 disassemble_operand!(code, true, wide);
540 print!("\t");
541 disassemble_jump_operand!(self, code, wide);
542 println!();
543 Ok(false)
544 }
545 JMPU => {
546 print!("JMPU({JMPU:#04x}) \t");
547 disassemble_operand!(code, true, wide);
548 print!("\t");
549 disassemble_jump_operand!(self, code, wide);
550 println!();
551 Ok(false)
552 }
553 JMPNU => {
554 print!("JMPNU({JMPNU:#04x}) \t");
555 disassemble_operand!(code, true, wide);
556 print!("\t");
557 disassemble_jump_operand!(self, code, wide);
558 println!();
559 Ok(false)
560 }
561 JMPRU => {
562 print!("JMPRU({JMPRU:#04x}) \t");
563 disassemble_operand!(code, true, wide);
564 print!("\t");
565 disassemble_immediate!(code, wide);
566 print!("\t");
567 disassemble_jump_operand!(self, code, wide);
568 println!();
569 Ok(false)
570 }
571 JMPRNU => {
572 print!("JMPRNU({JMPRNU:#04x}) \t");
573 disassemble_operand!(code, true, wide);
574 print!("\t");
575 disassemble_immediate!(code, wide);
576 print!("\t");
577 disassemble_jump_operand!(self, code, wide);
578 println!();
579 Ok(false)
580 }
581 ADD => {
582 print!("ADD \t");
583 disassemble_operand!(code, true, wide);
584 print!("\t");
585 disassemble_operand!(code, true, wide);
586 println!();
587 Ok(false)
588 }
589 SUB => {
590 print!("SUB \t");
591 disassemble_operand!(code, true, wide);
592 print!("\t");
593 disassemble_operand!(code, true, wide);
594 println!();
595 Ok(false)
596 }
597 MUL => {
598 print!("MUL \t");
599 disassemble_operand!(code, true, wide);
600 print!("\t");
601 disassemble_operand!(code, true, wide);
602 println!();
603 Ok(false)
604 }
605 DIV => {
606 print!("DIV \t");
607 disassemble_operand!(code, true, wide);
608 print!("\t");
609 disassemble_operand!(code, true, wide);
610 println!();
611 Ok(false)
612 }
613 NUMEQ => {
614 print!("NUMEQ \t");
615 disassemble_operand!(code, true, wide);
616 print!("\t");
617 disassemble_operand!(code, true, wide);
618 print!("\t");
619 disassemble_operand!(code, true, wide);
620 println!();
621 Ok(false)
622 }
623 NUMLT => {
624 print!("NUMLT \t");
625 disassemble_operand!(code, true, wide);
626 print!("\t");
627 disassemble_operand!(code, true, wide);
628 print!("\t");
629 disassemble_operand!(code, true, wide);
630 println!();
631 Ok(false)
632 }
633 NUMGT => {
634 print!("NUMGT \t");
635 disassemble_operand!(code, true, wide);
636 print!("\t");
637 disassemble_operand!(code, true, wide);
638 print!("\t");
639 disassemble_operand!(code, true, wide);
640 println!();
641 Ok(false)
642 }
643 NUMLTE => {
644 print!("NUMLTE \t");
645 disassemble_operand!(code, true, wide);
646 print!("\t");
647 disassemble_operand!(code, true, wide);
648 print!("\t");
649 disassemble_operand!(code, true, wide);
650 println!();
651 Ok(false)
652 }
653 NUMGTE => {
654 print!("NUMGTE \t");
655 disassemble_operand!(code, true, wide);
656 print!("\t");
657 disassemble_operand!(code, true, wide);
658 print!("\t");
659 disassemble_operand!(code, true, wide);
660 println!();
661 Ok(false)
662 }
663 INC => {
664 print!("INC \t");
665 disassemble_operand!(code, true, wide);
666 print!("\t");
667 disassemble_immediate!(code, wide);
668 println!();
669 Ok(false)
670 }
671 DEC => {
672 print!("DEC \t");
673 disassemble_operand!(code, true, wide);
674 print!("\t");
675 disassemble_immediate!(code, wide);
676 println!();
677 Ok(false)
678 }
679 CONS => {
680 print!("CONS \t");
681 print!("R(");
683 disassemble_operand!(code, true, wide);
684 print!(")");
685 print!("\tconscell(R(");
686 disassemble_operand!(code, true, wide);
687 print!("), R(");
688 disassemble_operand!(code, true, wide);
689 print!(")");
690 println!();
691 Ok(false)
692 }
693 CAR => {
694 print!("CAR ");
695 disassemble_operand!(code, true, wide);
696 print!("\t");
697 disassemble_operand!(code, true, wide);
698 println!();
699 Ok(false)
700 }
701 CDR => {
702 print!("CDR ");
703 disassemble_operand!(code, true, wide);
704 print!("\t");
705 disassemble_operand!(code, true, wide);
706 println!();
707 Ok(false)
708 }
709 XAR => {
710 print!("XAR ");
711 disassemble_operand!(code, true, wide);
712 print!("\t");
713 disassemble_operand!(code, true, wide);
714 println!();
715 Ok(false)
716 }
717 XDR => {
718 print!("XDR ");
719 disassemble_operand!(code, true, wide);
720 print!("\t");
721 disassemble_operand!(code, true, wide);
722 println!();
723 Ok(false)
724 }
725 LIST => {
726 print!("LIST \t");
727 disassemble_operand!(code, true, wide);
729 print!("\t");
730 disassemble_operand!(code, true, wide);
731 print!("\t");
732 disassemble_operand!(code, true, wide);
733 println!();
734 Ok(false)
735 }
736 APND => {
737 print!("APND \t");
738 disassemble_operand!(code, true, wide);
739 print!("\t");
740 disassemble_operand!(code, true, wide);
741 print!("\t");
742 disassemble_operand!(code, true, wide);
743 println!();
744 Ok(false)
745 }
746 VECMK => {
747 print!("VECMK \t");
748 disassemble_operand!(code, true, wide);
749 print!("\t");
750 disassemble_operand!(code, true, wide);
751 println!();
752 Ok(false)
753 }
754 VECELS => {
755 print!("VECELS \t");
756 disassemble_operand!(code, true, wide);
757 print!("\t");
758 disassemble_operand!(code, true, wide);
759 println!();
760 Ok(false)
761 }
762 VECPSH => {
763 print!("VECPSH \t");
764 disassemble_operand!(code, true, wide);
765 print!("\t");
766 disassemble_operand!(code, true, wide);
767 println!();
768 Ok(false)
769 }
770 VECPOP => {
771 print!("VECPOP \t");
772 disassemble_operand!(code, true, wide);
773 print!("\t");
774 disassemble_operand!(code, true, wide);
775 println!();
776 Ok(false)
777 }
778 VECMKD => {
779 print!("VECMKD \t");
780 disassemble_operand!(code, true, wide);
781 print!("\t");
782 disassemble_operand!(code, true, wide);
783 print!("\t");
784 disassemble_operand!(code, true, wide);
785 println!();
786 Ok(false)
787 }
788 VEC => {
789 print!("VEC \t");
790 disassemble_operand!(code, true, wide);
792 print!("\t");
793 disassemble_operand!(code, true, wide);
794 print!("\t");
795 disassemble_operand!(code, true, wide);
796 println!();
797 Ok(false)
798 }
799 MAPMK => {
800 print!("MAPMK \t");
801 disassemble_operand!(code, true, wide);
802 print!("\t");
803 disassemble_operand!(code, true, wide);
804 print!("\t");
805 disassemble_operand!(code, true, wide);
806 println!();
807 Ok(false)
808 }
809 LEN => {
810 print!("LEN \t");
811 disassemble_operand!(code, true, wide);
812 print!("\t");
813 disassemble_operand!(code, true, wide);
814 println!();
815 Ok(false)
816 }
817 CLR => {
818 print!("CLR \t");
819 disassemble_operand!(code, true, wide);
820 println!();
821 Ok(false)
822 }
823 STR => {
824 print!("STR \t");
825 disassemble_operand!(code, true, wide);
826 print!("\t");
827 disassemble_operand!(code, true, wide);
828 print!("\t");
829 disassemble_operand!(code, true, wide);
830 println!();
831 Ok(false)
832 }
833 TYPE => {
834 print!("TYPE \t");
835 disassemble_operand!(code, true, wide);
836 print!("\t");
837 disassemble_operand!(code, true, wide);
838 println!();
839 Ok(false)
840 }
841 _ => Err(VMError::new_chunk(format!("ERROR: unknown opcode {op}"))),
842 }
843 }
844
845 pub fn disassemble_chunk<ENV>(&self, vm: &GVm<ENV>, indent_level: u16) -> VMResult<()> {
846 fn indent(indent_level: u16) {
847 for _ in 0..indent_level {
848 print!("\t");
849 }
850 }
851 indent(indent_level);
852 println!(
853 "INPUTS: {} args/optional/rest {}/{}/{}",
854 self.input_regs, self.args, self.opt_args, self.rest
855 );
856 indent(indent_level);
857 println!("EXTRA REGS: {}", self.extra_regs);
858 indent(indent_level);
859 println!("CONSTANTS:");
860 for (i, v) in self.constants.iter().enumerate() {
861 indent(indent_level);
862 println!("{}: {}", i, v.display_value(vm));
863 match v {
864 Value::Lambda(h) => vm.get_lambda(*h).disassemble_chunk(vm, indent_level + 1)?,
865 Value::Closure(h) => vm.get_lambda(*h).disassemble_chunk(vm, indent_level + 1)?,
866 _ => {}
867 }
868 }
869 println!();
870 if let Some(caps) = &self.captures {
871 indent(indent_level);
872 println!("Captures: {caps:?}");
873 }
874 let mut code = self.code.iter().cloned().enumerate();
875 let mut op = code.next();
876 let mut last_line = 0;
877 let mut wide = false;
878 while let Some((idx, curr_op)) = op {
879 indent(indent_level);
880 print!("{idx:#010x} ");
881 if let Some(line_number) = self.offset_to_line(idx) {
882 if last_line != line_number {
883 print!("{line_number:>6} ");
884 last_line = line_number;
885 } else {
886 print!(" | ");
887 }
888 } else {
889 print!(" | ");
890 }
891 wide = self.disassemble_instruction(&mut code, curr_op, wide, vm)?;
892 op = code.next();
893 }
894 Ok(())
895 }
896}