slvm/chunk/
disassemble.rs

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                //R(A) = conscell(R(B), R(C))
682                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                //println!("{:#06x} ", decode_u16_enum!(code)?);
728                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                //println!("{:#06x} ", decode_u16_enum!(code)?);
791                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}